beetle-pce-fast-libretro/libretro.cpp

1905 lines
46 KiB
C++
Raw Normal View History

2014-11-20 03:28:28 +00:00
#include <stdarg.h>
2012-06-03 15:48:14 +00:00
#include "mednafen/mednafen.h"
#include "mednafen/git.h"
#include "mednafen/general.h"
#include "libretro.h"
2014-06-18 20:10:07 +00:00
#include "thread.h"
2012-06-03 15:48:14 +00:00
2014-11-20 03:28:28 +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/cdrom/cdromif.h"
#include "mednafen/cdrom/CDUtility.h"
#ifdef _MSC_VER
2014-06-24 23:57:10 +00:00
#include "mednafen/msvc_compat.h"
#endif
2014-06-20 20:49:22 +00:00
static bool old_cdimagecache = false;
extern MDFNGI EmulatedPCE_Fast;
2014-11-20 03:28:28 +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
*/
2014-11-20 03:28:28 +00:00
extern "C" unsigned long crc32(unsigned long crc, const unsigned char* buf,
unsigned int len);
2014-06-19 21:10:59 +00:00
namespace PCE_Fast
{
2014-11-20 03:28:28 +00:00
static PCEFast_PSG* psg = NULL;
extern ArcadeCard* arcade_card; // Bah, lousy globals.
2014-06-19 21:10:59 +00:00
static Blip_Buffer sbuf[2];
bool PCE_ACEnabled;
int pce_overclocked;
// Statically allocated for speed...or something.
2014-11-20 03:28:28 +00:00
uint8 ROMSpace[0x88 * 8192 + 8192]; // + 8192 for PC-as-pointer safety padding
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
uint8 BaseRAM[32768 +
8192]; // 8KB for PCE, 32KB for Super Grafx // + 8192 for PC-as-pointer safety padding
2014-06-19 21:10:59 +00:00
uint8 PCEIODataBuffer;
readfunc PCERead[0x100];
writefunc PCEWrite[0x100];
static DECLFR(PCEBusRead)
{
2014-11-20 03:28:28 +00:00
//printf("BUS Read: %02x %04x\n", A >> 13, A);
return (0xFF);
2014-06-19 21:10:59 +00:00
}
static DECLFW(PCENullWrite)
{
2014-11-20 03:28:28 +00:00
//printf("Null Write: %02x, %08x %02x\n", A >> 13, A, V);
2014-06-19 21:10:59 +00:00
}
static DECLFR(BaseRAMRead)
{
2014-11-20 03:28:28 +00:00
return ((BaseRAM - (0xF8 * 8192))[A]);
2014-06-19 21:10:59 +00:00
}
static DECLFR(BaseRAMRead_Mirrored)
{
2014-11-20 03:28:28 +00:00
return (BaseRAM[A & 0x1FFF]);
2014-06-19 21:10:59 +00:00
}
static DECLFW(BaseRAMWrite)
{
2014-11-20 03:28:28 +00:00
(BaseRAM - (0xF8 * 8192))[A] = V;
2014-06-19 21:10:59 +00:00
}
static DECLFW(BaseRAMWrite_Mirrored)
{
2014-11-20 03:28:28 +00:00
BaseRAM[A & 0x1FFF] = V;
2014-06-19 21:10:59 +00:00
}
static DECLFR(IORead)
{
2014-11-20 03:28:28 +00:00
#include "mednafen/pce_fast/ioread.inc"
2014-06-19 21:10:59 +00:00
}
static DECLFW(IOWrite)
{
2014-11-20 03:28:28 +00:00
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.
}
2014-06-19 21:10:59 +00:00
}
static void PCECDIRQCB(bool asserted)
{
2014-11-20 03:28:28 +00:00
if (asserted)
HuC6280_IRQBegin(MDFN_IQIRQ2);
else
HuC6280_IRQEnd(MDFN_IQIRQ2);
2014-06-19 21:10:59 +00:00
}
bool PCE_InitCD(void)
{
2014-11-20 03:28:28 +00:00
PCECD_Settings cd_settings;
memset(&cd_settings, 0, sizeof(PCECD_Settings));
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
cd_settings.CDDA_Volume = (double)MDFN_GetSettingUI("pce_fast.cddavolume") /
100;
cd_settings.CD_Speed = MDFN_GetSettingUI("pce_fast.cdspeed");
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
cd_settings.ADPCM_Volume = (double)MDFN_GetSettingUI("pce_fast.adpcmvolume") /
100;
cd_settings.ADPCM_LPF = MDFN_GetSettingB("pce_fast.adpcmlp");
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
if (cd_settings.CDDA_Volume != 1.0)
MDFN_printf(("CD-DA Volume: %d%%\n"), (int)(100 * cd_settings.CDDA_Volume));
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
if (cd_settings.ADPCM_Volume != 1.0)
MDFN_printf(("ADPCM Volume: %d%%\n"), (int)(100 * cd_settings.ADPCM_Volume));
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
return (PCECD_Init(&cd_settings, PCECDIRQCB, PCE_MASTER_CLOCK, pce_overclocked,
&sbuf[0], &sbuf[1]));
2014-06-19 21:10:59 +00:00
}
static int LoadCommon(void);
static void LoadCommonPre(void);
2014-11-20 03:28:28 +00:00
static int Load(const char* name, MDFNFILE* fp)
2014-06-19 21:10:59 +00:00
{
2014-11-20 03:28:28 +00:00
uint32 headerlen = 0;
uint32 r_size;
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
LoadCommonPre();
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
{
if (GET_FSIZE_PTR(fp) & 0x200) // 512 byte header!
headerlen = 512;
}
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
r_size = GET_FSIZE_PTR(fp) - headerlen;
if (r_size > 4096 * 1024) r_size = 4096 * 1024;
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
for (int x = 0; x < 0x100; x++)
{
PCERead[x] = PCEBusRead;
PCEWrite[x] = PCENullWrite;
}
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
uint32 crc = crc32(0, GET_FDATA_PTR(fp) + headerlen,
GET_FSIZE_PTR(fp) - headerlen);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
HuCLoad(GET_FDATA_PTR(fp) + headerlen, GET_FSIZE_PTR(fp) - headerlen, crc);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
return (LoadCommon());
2014-06-19 21:10:59 +00:00
}
static void LoadCommonPre(void)
{
2014-11-20 03:28:28 +00:00
// FIXME: Make these globals less global!
pce_overclocked = MDFN_GetSettingUI("pce_fast.ocmultiplier");
PCE_ACEnabled = MDFN_GetSettingB("pce_fast.arcadecard");
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
if (pce_overclocked > 1)
MDFN_printf(("CPU overclock: %dx\n"), pce_overclocked);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
if (MDFN_GetSettingUI("pce_fast.cdspeed") > 1)
MDFN_printf(("CD-ROM speed: %ux\n"),
(unsigned int)MDFN_GetSettingUI("pce_fast.cdspeed"));
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
memset(HuCPUFastMap, 0, sizeof(HuCPUFastMap));
for (int x = 0; x < 0x100; x++)
{
PCERead[x] = PCEBusRead;
PCEWrite[x] = PCENullWrite;
}
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
// MDFNMP_Init(1024, (1 << 21) / 1024);
2014-06-19 21:10:59 +00:00
}
static int LoadCommon(void)
2014-11-20 03:28:28 +00:00
{
VDC_Init(false);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
{
PCERead[0xF8] = BaseRAMRead;
PCERead[0xF9] = PCERead[0xFA] = PCERead[0xFB] = BaseRAMRead_Mirrored;
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
PCEWrite[0xF8] = BaseRAMWrite;
PCEWrite[0xF9] = PCEWrite[0xFA] = PCEWrite[0xFB] = BaseRAMWrite_Mirrored;
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
for (int x = 0xf8; x < 0xfb; x++)
HuCPUFastMap[x] = BaseRAM - x * 8192;
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
PCERead[0xFF] = IORead;
}
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
// MDFNMP_AddRAM(8192, 0xf8 * 8192, BaseRAM);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
PCEWrite[0xFF] = IOWrite;
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
HuC6280_Init();
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
psg = new PCEFast_PSG(&sbuf[0], &sbuf[1]);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
psg->SetVolume(1.0);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
if (PCE_IsCD)
{
unsigned int cdpsgvolume = MDFN_GetSettingUI("pce_fast.cdpsgvolume");
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
if (cdpsgvolume != 100)
MDFN_printf(("CD PSG Volume: %d%%\n"), cdpsgvolume);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
psg->SetVolume(0.678 * cdpsgvolume / 100);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
}
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
PCEINPUT_Init();
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
PCE_Power();
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
MDFNGameInfo->LayerNames = "Background\0Sprites\0";
MDFNGameInfo->fps = (uint32)((double)7159090.90909090 / 455 / 263 * 65536 *
256);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
// Clean this up:
if (!MDFN_GetSettingB("pce_fast.correct_aspect"))
MDFNGameInfo->fb_width = 682;
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
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;
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
MDFNGameInfo->lcm_width = MDFN_GetSettingB("pce_fast.correct_aspect") ? 1024 :
341;
MDFNGameInfo->lcm_height = MDFNGameInfo->nominal_height;
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
return (1);
2014-06-19 21:10:59 +00:00
}
2014-11-20 03:28:28 +00:00
static bool TestMagicCD(std::vector<CDIF*>* CDInterfaces)
2014-06-19 21:10:59 +00:00
{
2014-11-20 03:28:28 +00:00
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;
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
memset(sector_buffer, 0, sizeof(sector_buffer));
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
cdiface->ReadTOC(&toc);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
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);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
if (!memcmp((char*)sector_buffer, (char*)magic_test, 0x20))
ret = TRUE;
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
// PCE CD BIOS apparently only looks at the first data track.
break;
}
}
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
// 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++)
2014-06-19 21:10:59 +00:00
{
2014-11-20 03:28:28 +00:00
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);
}
2014-06-19 21:10:59 +00:00
}
2014-11-20 03:28:28 +00:00
// 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))
2014-06-19 21:10:59 +00:00
{
2014-11-20 03:28:28 +00:00
if (cdiface->ReadSector(sector_buffer, 0x10, 1))
{
if (!memcmp((char*)sector_buffer + 0x8, "HACKER CD ROM SYSTEM", 0x14))
ret = TRUE;
}
2014-06-19 21:10:59 +00:00
}
2014-11-20 03:28:28 +00:00
return (ret);
2014-06-19 21:10:59 +00:00
}
2014-11-20 03:28:28 +00:00
static int LoadCD(std::vector<CDIF*>* CDInterfaces)
2014-06-19 21:10:59 +00:00
{
2014-11-20 03:28:28 +00:00
std::string bios_path = MDFN_MakeFName(MDFNMKF_FIRMWARE, 0,
MDFN_GetSettingS("pce_fast.cdbios").c_str());
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
LoadCommonPre();
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
if (!HuCLoadCD(bios_path.c_str()))
return (0);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
PCECD_Drive_SetDisc(true, NULL, true);
PCECD_Drive_SetDisc(false, (*CDInterfaces)[0], true);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
return (LoadCommon());
2014-06-19 21:10:59 +00:00
}
2014-06-20 21:11:19 +00:00
static void Cleanup_PCE(void)
{
HuC_Close();
VDC_Close();
2014-11-20 03:28:28 +00:00
if (psg)
2014-06-20 21:11:19 +00:00
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
}
2014-11-20 03:28:28 +00:00
static void Emulate(EmulateSpecStruct* espec)
2014-06-19 21:10:59 +00:00
{
2014-11-20 03:28:28 +00:00
INPUT_Frame();
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
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);
}
}
2014-11-19 00:31:56 +00:00
2014-11-20 03:28:28 +00:00
RETRO_PERFORMANCE_INIT(VDC_RunFrame_time);
RETRO_PERFORMANCE_START(VDC_RunFrame_time);
2014-11-19 00:31:56 +00:00
#if defined(DUMP_FRAME_TIMES) && defined(PERF_TEST)
2014-11-20 03:28:28 +00:00
retro_perf_tick_t start_ticks = VDC_RunFrame_time.total;
2014-11-19 00:31:56 +00:00
#endif
2014-11-20 03:28:28 +00:00
PSPPROF_START;
// if (VDC_RunFrame_time.call_cnt == 44)
// printf("halt\n");
VDC_RunFrame(espec, false);
PSPPROF_STOP;
RETRO_PERFORMANCE_STOP(VDC_RunFrame_time);
2014-11-19 00:31:56 +00:00
#if defined(DUMP_FRAME_TIMES) && defined(PERF_TEST)
2014-11-20 03:28:28 +00:00
printf("%u : %u ticks\n", (uint32_t)VDC_RunFrame_time.call_cnt,
(uint32_t)(VDC_RunFrame_time.total - start_ticks));
fflush(stdout);
2014-11-19 00:31:56 +00:00
#endif
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
if (PCE_IsCD)
PCECD_Run(HuCPU.timestamp * 3);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
psg->EndFrame(HuCPU.timestamp / pce_overclocked);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
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);
}
}
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
espec->MasterCycles = HuCPU.timestamp * 3;
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
INPUT_FixTS();
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
HuC6280_ResetTS();
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
if (PCE_IsCD)
PCECD_ResetTS();
2014-06-19 21:10:59 +00:00
}
2014-11-20 03:28:28 +00:00
static int StateAction(StateMem* sm, int load, int data_only)
2014-06-19 21:10:59 +00:00
{
2014-11-20 03:28:28 +00:00
SFORMAT StateRegs[] =
{
SFARRAY(BaseRAM, 8192),
SFVAR(PCEIODataBuffer),
SFEND
};
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
//for(int i = 8192; i < 32768; i++)
// if(BaseRAM[i] != 0xFF)
// printf("%d %02x\n", i, BaseRAM[i]);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "MAIN");
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +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);
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
if (load)
{
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
}
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
return (ret);
2014-06-19 21:10:59 +00:00
}
void PCE_Power(void)
{
2014-11-20 03:28:28 +00:00
memset(BaseRAM, 0x00, sizeof(BaseRAM));
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
for (int i = 8192; i < 32768; i++)
BaseRAM[i] = 0xFF;
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
PCEIODataBuffer = 0xFF;
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
HuC6280_Power();
VDC_Power();
psg->Power(HuCPU.timestamp / pce_overclocked);
HuC_Power();
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
if (PCE_IsCD)
PCECD_Power(HuCPU.timestamp * 3);
2014-06-19 21:10:59 +00:00
}
static void DoSimpleCommand(int cmd)
{
2014-11-20 03:28:28 +00:00
switch (cmd)
{
case MDFN_MSC_RESET:
PCE_Power();
break;
case MDFN_MSC_POWER:
PCE_Power();
break;
}
2014-06-19 21:10:59 +00:00
}
2014-11-20 03:28:28 +00:00
static MDFNSetting PCESettings[] =
2014-06-19 21:10:59 +00:00
{
2014-11-20 03:28:28 +00:00
{ "pce_fast.correct_aspect", MDFNSF_CAT_VIDEO, ("Correct the aspect ratio."), NULL, MDFNST_BOOL, "1" },
{ "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" },
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
{ "pce_fast.cdbios", MDFNSF_EMU_STATE, ("Path to the CD BIOS"), NULL, MDFNST_STRING, "syscard3.pce" },
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +00:00
{ "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" },
{ NULL }
2014-06-19 21:10:59 +00:00
};
static uint8 MemRead(uint32 addr)
{
2014-11-20 03:28:28 +00:00
return (PCERead[(addr / 8192) & 0xFF](addr));
2014-06-19 21:10:59 +00:00
}
static const FileExtensionSpecStruct KnownExtensions[] =
{
2014-11-20 03:28:28 +00:00
{ ".pce", ("PC Engine ROM Image") },
{ NULL, NULL }
2014-06-19 21:10:59 +00:00
};
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";
2014-11-20 03:28:28 +00:00
ArcadeCard* arcade_card = NULL;
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
static uint8* HuCROM = NULL;
2014-06-20 17:54:30 +00:00
static bool IsPopulous;
bool PCE_IsCD;
uint8 SaveRAM[2048];
static DECLFW(ACPhysWrite)
{
2014-11-20 03:28:28 +00:00
arcade_card->PhysWrite(A, V);
2014-06-20 17:54:30 +00:00
}
static DECLFR(ACPhysRead)
{
2014-11-20 03:28:28 +00:00
return (arcade_card->PhysRead(A));
2014-06-20 17:54:30 +00:00
}
static DECLFR(SaveRAMRead)
{
2014-11-20 03:28:28 +00:00
if ((!PCE_IsCD || PCECD_IsBRAMEnabled()) && (A & 8191) < 2048)
return (SaveRAM[A & 2047]);
else
return (0xFF);
2014-06-20 17:54:30 +00:00
}
static DECLFW(SaveRAMWrite)
{
2014-11-20 03:28:28 +00:00
if ((!PCE_IsCD || PCECD_IsBRAMEnabled()) && (A & 8191) < 2048)
SaveRAM[A & 2047] = V;
2014-06-20 17:54:30 +00:00
}
static DECLFR(HuCRead)
{
2014-11-20 03:28:28 +00:00
return ROMSpace[A];
2014-06-20 17:54:30 +00:00
}
static DECLFW(HuCRAMWrite)
{
2014-11-20 03:28:28 +00:00
ROMSpace[A] = V;
2014-06-20 17:54:30 +00:00
}
static DECLFW(HuCRAMWriteCDSpecial) // Hyper Dyne Special hack
{
2014-11-20 03:28:28 +00:00
BaseRAM[0x2000 | (A & 0x1FFF)] = V;
ROMSpace[A] = V;
2014-06-20 17:54:30 +00:00
}
static uint8 HuCSF2Latch = 0;
static DECLFR(HuCSF2Read)
{
2014-11-20 03:28:28 +00:00
return (HuCROM[(A & 0x7FFFF) + 0x80000 + HuCSF2Latch *
0x80000 ]); // | (HuCSF2Latch << 19) ]);
2014-06-20 17:54:30 +00:00
}
static DECLFW(HuCSF2Write)
{
2014-11-20 03:28:28 +00:00
if ((A & 0x1FFC) == 0x1FF0)
HuCSF2Latch = (A & 0x3);
2014-06-20 17:54:30 +00:00
}
2014-06-20 21:11:19 +00:00
static void Cleanup(void)
{
2014-11-20 03:28:28 +00:00
if (arcade_card)
2014-06-20 21:11:19 +00:00
delete arcade_card;
arcade_card = NULL;
2014-11-20 03:28:28 +00:00
if (PCE_IsCD)
2014-06-20 21:11:19 +00:00
PCECD_Close();
2014-11-20 03:28:28 +00:00
if (HuCROM)
2014-06-20 21:11:19 +00:00
MDFN_free(HuCROM);
HuCROM = NULL;
}
2014-11-20 03:28:28 +00:00
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;
MDFN_printf(("ROM: %dKiB\n"), (len + 1023) / 1024);
MDFN_printf(("ROM CRC32: 0x%04x\n"), crc32);
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);
}
2014-06-20 17:54:30 +00:00
bool IsBRAMUsed(void)
{
2014-11-20 03:28:28 +00:00
if (memcmp(SaveRAM, BRAM_Init_String, 8)) // HUBM string is modified/missing
return (1);
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
for (int x = 8; x < 2048; x++)
if (SaveRAM[x]) return (1);
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
return (0);
2014-06-20 17:54:30 +00:00
}
2014-11-20 03:28:28 +00:00
int HuCLoadCD(const char* bios_path)
2014-06-20 17:54:30 +00:00
{
2014-11-20 03:28:28 +00:00
static const FileExtensionSpecStruct KnownBIOSExtensions[] =
{
{ ".pce", ("PC Engine ROM Image") },
{ ".bin", ("PC Engine ROM Image") },
{ ".bios", ("BIOS Image") },
{ NULL, NULL }
};
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
MDFNFILE fp = {0};
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
if (!MDFNFILE_Open(&fp, bios_path, KnownBIOSExtensions, ("CD BIOS")))
return (0);
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
memset(ROMSpace, 0xFF, 262144);
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
memcpy(ROMSpace, GET_FDATA(fp) + (GET_FSIZE(fp) & 512),
((GET_FSIZE(fp) & ~512) > 262144) ? 262144 : (GET_FSIZE(fp) & ~ 512));
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
MDFNFILE_Close(&fp);
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
PCE_IsCD = 1;
PCE_InitCD();
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
MDFN_printf(("Arcade Card Emulation: %s\n"),
PCE_ACEnabled ? ("Enabled") : ("Disabled"));
for (int x = 0; x < 0x40; x++)
{
HuCPUFastMap[x] = ROMSpace;
PCERead[x] = HuCRead;
}
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
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);
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
if (PCE_ACEnabled)
{
if (!(arcade_card = new ArcadeCard()))
{
MDFN_PrintError(("Error creating %s object.\n"), "ArcadeCard");
Cleanup();
return (0);
}
2014-06-20 21:11:19 +00:00
2014-11-20 03:28:28 +00:00
for (int x = 0x40; x < 0x44; x++)
{
HuCPUFastMap[x] = NULL;
PCERead[x] = ACPhysRead;
PCEWrite[x] = ACPhysWrite;
}
}
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +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.
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
PCEWrite[0xF7] = SaveRAMWrite;
PCERead[0xF7] = SaveRAMRead;
// MDFNMP_AddRAM(2048, 0xF7 * 8192, SaveRAM);
return (1);
2014-06-20 17:54:30 +00:00
}
2014-11-20 03:28:28 +00:00
int HuC_StateAction(StateMem* sm, int load, int data_only)
2014-06-20 17:54:30 +00:00
{
2014-11-20 03:28:28 +00:00
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");
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
if (load)
HuCSF2Latch &= 0x3;
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
if (PCE_IsCD)
{
ret &= PCECD_StateAction(sm, load, data_only);
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
if (arcade_card)
ret &= arcade_card->StateAction(sm, load, data_only);
}
return (ret);
2014-06-20 17:54:30 +00:00
}
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)
{
2014-11-20 03:28:28 +00:00
if (PCE_IsCD)
memset(ROMSpace + 0x68 * 8192, 0x00, 262144);
2014-06-20 17:54:30 +00:00
2014-11-20 03:28:28 +00:00
if (arcade_card)
arcade_card->Power();
2014-06-20 17:54:30 +00:00
}
2014-06-19 21:10:59 +00:00
};
MDFNGI EmulatedPCE_Fast =
{
2014-11-20 03:28:28 +00:00
"pce_fast",
"PC Engine (CD)/TurboGrafx 16 (CD)/SuperGrafx",
KnownExtensions,
MODPRIO_INTERNAL_LOW,
NULL,
&PCEInputInfo,
Load,
LoadCD,
TestMagicCD,
CloseGame,
VDC_SetLayerEnableMask,
NULL,
NULL,
NULL,
NULL,
NULL,
MemRead,
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:10:59 +00:00
};
2014-11-20 03:28:28 +00:00
static void ReadM3U(std::vector<std::string> &file_list, std::string path,
unsigned depth = 0)
{
2014-11-20 03:28:28 +00:00
std::vector<std::string> ret;
FileWrapper m3u_file(path.c_str(), FileWrapper::MODE_READ, ("M3U CD Set"));
std::string dir_path;
char linebuf[2048];
2014-11-20 03:28:28 +00:00
MDFN_GetFilePathComponents(path, &dir_path);
2014-11-20 03:28:28 +00:00
while (m3u_file.get_line(linebuf, sizeof(linebuf)))
{
std::string efp;
2014-11-20 03:28:28 +00:00
if (linebuf[0] == '#') continue;
MDFN_rtrim(linebuf);
if (linebuf[0] == 0) continue;
2014-11-20 03:28:28 +00:00
efp = MDFN_EvalFIP(dir_path, std::string(linebuf));
2014-11-20 03:28:28 +00:00
if (efp.size() >= 4 && efp.substr(efp.size() - 4) == ".m3u")
{
assert(efp != path);
// throw(MDFN_Error(0, ("M3U at \"%s\" references self."), efp.c_str()));
2014-11-20 03:28:28 +00:00
assert(depth != 99);
// throw(MDFN_Error(0, ("M3U load recursion too deep!")));
2014-11-20 03:28:28 +00:00
ReadM3U(file_list, efp, depth++);
}
else
file_list.push_back(efp);
}
}
2014-11-20 03:28:28 +00:00
static std::vector<CDIF*> CDInterfaces; // FIXME: Cleanup on error out.
// TODO: LoadCommon()
2014-11-20 03:28:28 +00:00
MDFNGI* MDFNI_LoadCD(const char* force_module, const char* devicename)
{
2014-11-20 03:28:28 +00:00
uint8 LayoutMD5[16];
2014-11-20 03:28:28 +00:00
MDFN_printf(("Loading %s...\n\n"), devicename ? devicename : ("PHYSICAL CD"));
2014-11-20 03:28:28 +00:00
try
{
if (devicename && strlen(devicename) > 4
&& !strcasecmp(devicename + strlen(devicename) - 4, ".m3u"))
{
std::vector<std::string> file_list;
2014-11-20 03:28:28 +00:00
ReadM3U(file_list, devicename);
2014-11-20 03:28:28 +00:00
for (unsigned i = 0; i < file_list.size(); i++)
CDInterfaces.push_back(CDIF_Open(file_list[i].c_str(), false,
old_cdimagecache));
}
else
CDInterfaces.push_back(CDIF_Open(devicename, false, old_cdimagecache));
}
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++)
{
2014-11-20 03:28:28 +00:00
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");
}
2014-11-20 03:28:28 +00:00
MDFN_indent(-1);
// 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);
}
MDFNGI* MDFNI_LoadGame(const char* force_module, const char* name)
{
MDFNFILE GameFile = {0};
std::vector<FileExtensionSpecStruct> valid_iae;
MDFNGameInfo = &EmulatedPCE_Fast;
2014-11-20 03:28:28 +00:00
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));
2014-11-20 03:28:28 +00:00
MDFN_printf(("Loading %s...\n"), name);
2014-11-20 03:28:28 +00:00
MDFN_indent(1);
2014-11-20 03:28:28 +00:00
// Construct a NULL-delimited list of known file extensions for MDFN_fopen()
const FileExtensionSpecStruct* curexts = MDFNGameInfo->FileExtensions;
2014-11-20 03:28:28 +00:00
while (curexts->extension && curexts->description)
{
valid_iae.push_back(*curexts);
curexts++;
}
2014-11-20 03:28:28 +00:00
if (!MDFNFILE_Open(&GameFile, name, &valid_iae[0], ("game")))
{
MDFNGameInfo = NULL;
return 0;
}
2014-11-20 03:28:28 +00:00
MDFN_printf(("Using module: %s(%s)\n\n"), MDFNGameInfo->shortname,
MDFNGameInfo->fullname);
MDFN_indent(1);
2014-11-20 03:28:28 +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-11-20 03:28:28 +00:00
if (MDFNGameInfo->Load(name, &GameFile) <= 0)
{
2014-11-20 03:28:28 +00:00
MDFNFILE_Close(&GameFile);
MDFN_indent(-2);
MDFNGameInfo = NULL;
2014-11-20 03:28:28 +00:00
return (0);
}
2014-11-20 03:28:28 +00:00
// MDFN_LoadGameCheats(NULL);
// MDFNMP_InstallReadPatches();
2014-11-20 03:28:28 +00:00
MDFN_indent(-2);
2014-11-20 03:28:28 +00:00
if (!MDFNGameInfo->name)
{
unsigned int x;
2014-11-20 03:28:28 +00:00
char* tmp;
2014-11-20 03:28:28 +00:00
MDFNGameInfo->name = (UTF8*)strdup(GetFNComponent(name));
2014-11-20 03:28:28 +00:00
for (x = 0; x < strlen((char*)MDFNGameInfo->name); x++)
{
2014-11-20 03:28:28 +00:00
if (MDFNGameInfo->name[x] == '_')
MDFNGameInfo->name[x] = ' ';
}
2014-11-20 03:28:28 +00:00
if ((tmp = strrchr((char*)MDFNGameInfo->name, '.')))
* tmp = 0;
}
2014-11-20 03:28:28 +00:00
return (MDFNGameInfo);
}
static int curindent = 0;
void MDFN_indent(int indent)
{
2014-11-20 03:28:28 +00:00
curindent += indent;
}
static uint8 lastchar = 0;
2014-06-19 21:10:59 +00:00
2014-11-20 03:28:28 +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;
static bool overscan;
static double last_sound_rate;
2014-11-20 03:28:28 +00:00
static MDFN_Surface surf = {NULL, 0, 0, 0};
2012-06-03 15:48:14 +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;
std::string retro_save_directory;
2012-10-13 13:31:49 +00:00
2014-11-20 03:28:28 +00:00
static void set_basename(const char* path)
2013-04-27 14:40:24 +00:00
{
2014-11-20 03:28:28 +00:00
const char* base = strrchr(path, '/');
2013-04-27 14:40:24 +00:00
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
#define MEDNAFEN_CORE_NAME_MODULE "pce_fast"
#define MEDNAFEN_CORE_NAME "Mednafen PCE Fast"
2014-06-23 12:52:11 +00:00
#define MEDNAFEN_CORE_VERSION "v0.9.36.1"
2014-06-22 03:57:12 +00:00
#define MEDNAFEN_CORE_EXTENSIONS "pce|cue|ccd"
#define MEDNAFEN_CORE_TIMING_FPS 59.82
2014-06-20 22:31:52 +00:00
#define MEDNAFEN_CORE_GEOMETRY_BASE_W 288
#define MEDNAFEN_CORE_GEOMETRY_BASE_H 232
#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
#define FB_MAX_HEIGHT FB_HEIGHT
static void check_system_specs(void)
{
2014-06-23 01:12:05 +00:00
unsigned level = 5;
environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level);
}
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;
2014-11-20 03:28:28 +00:00
else
2014-01-02 01:50:09 +00:00
log_cb = NULL;
CDUtility::CDUtility_Init();
2012-06-03 15:48:14 +00:00
2014-11-20 03:28:28 +00:00
const char* dir = NULL;
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);
}
else
{
2013-12-17 01:24:08 +00:00
/* TODO: Add proper fallback */
if (log_cb)
2014-11-20 03:28:28 +00:00
log_cb(RETRO_LOG_WARN,
"System directory is not defined. Fallback on using same dir as ROM for system directory later ...\n");
failed_init = true;
}
if (environ_cb(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &dir) && dir)
{
2014-11-20 03:28:28 +00:00
// If save directory is defined use it, otherwise use system directory
retro_save_directory = *dir ? dir : retro_base_directory;
// 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++;
2014-11-20 03:28:28 +00:00
retro_save_directory = retro_save_directory.substr(0, last);
}
else
{
/* TODO: Add proper fallback */
if (log_cb)
2014-11-20 03:28:28 +00:00
log_cb(RETRO_LOG_WARN,
"Save directory is not defined. Fallback on using SYSTEM directory ...\n");
retro_save_directory = retro_base_directory;
}
2012-06-09 22:46:41 +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)
2014-11-20 03:28:28 +00:00
log_cb(RETRO_LOG_INFO,
"Frontend supports RGB565 - will use that instead of XRGB1555.\n");
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;
2014-11-20 03:28:28 +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
check_system_specs();
2014-11-18 22:14:37 +00:00
#ifdef PSP
PSPPROF_INIT;
#endif
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
}
2014-11-20 03:28:28 +00:00
bool retro_load_game_special(unsigned, const struct retro_game_info*, size_t)
2012-06-03 15:48:14 +00:00
{
return false;
}
2014-11-20 03:28:28 +00:00
static void set_volume(uint32_t* ptr, unsigned number)
{
2014-11-20 03:28:28 +00:00
switch (number)
{
2014-11-20 03:28:28 +00:00
default:
*ptr = number;
break;
}
}
2014-06-20 20:49:22 +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;
}
var.key = "pce_nospritelimit";
2014-06-20 20:49:22 +00:00
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
if (strcmp(var.value, "disabled") == 0)
setting_pce_fast_nospritelimit = 0;
else if (strcmp(var.value, "enabled") == 0)
setting_pce_fast_nospritelimit = 1;
}
var.key = "pce_keepaspect";
2014-06-20 20:49:22 +00:00
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
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;
}
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;
}
}
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);
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);
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)
{
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)
{
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)
{
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)
{
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;
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-12-17 01:24:08 +00:00
if (PCECD_SetSettings(&settings) && log_cb)
log_cb(RETRO_LOG_INFO, "PCE CD Audio settings changed.\n");
}
}
#define MAX_PLAYERS 5
#define MAX_BUTTONS 13
static uint8_t input_buf[MAX_PLAYERS][2] = {0};
2014-11-20 03:28:28 +00:00
bool retro_load_game(const struct retro_game_info* info)
2012-06-03 15:48:14 +00:00
{
if (failed_init)
return false;
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();
game = MDFNI_LoadGame(MEDNAFEN_CORE_NAME_MODULE, info->path);
if (!game)
return false;
2014-11-20 00:55:26 +00:00
surf.w = FB_WIDTH;
surf.h = FB_HEIGHT;
surf.pitchinpix = FB_WIDTH;
2014-11-20 03:28:28 +00:00
surf.pixels16 = (uint16*)calloc(FB_WIDTH * FB_HEIGHT, sizeof(uint16));
2014-11-20 00:55:26 +00:00
2012-10-13 13:31:49 +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;
}
void retro_unload_game(void)
2012-06-03 15:48:14 +00:00
{
2014-11-20 03:28:28 +00:00
if (!MDFNGameInfo)
2013-01-19 09:22:57 +00:00
return;
2014-11-20 03:28:28 +00:00
// MDFN_FlushGameCheats(0);
MDFNGameInfo->CloseGame();
2014-11-20 03:28:28 +00:00
if (MDFNGameInfo->name)
free(MDFNGameInfo->name);
MDFNGameInfo->name = NULL;
2012-06-03 15:48:14 +00:00
2014-11-20 03:28:28 +00:00
// MDFNMP_Kill();
MDFNGameInfo = NULL;
2014-11-20 03:28:28 +00:00
for (unsigned i = 0; i < CDInterfaces.size(); i++)
delete CDInterfaces[i];
CDInterfaces.clear();
}
static void update_input(void)
2012-06-03 16:58:46 +00:00
{
2014-11-20 03:28:28 +00:00
static unsigned map[] =
{
2012-11-22 20:03:38 +00:00
RETRO_DEVICE_ID_JOYPAD_A,
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,
RETRO_DEVICE_ID_JOYPAD_X,
RETRO_DEVICE_ID_JOYPAD_L,
RETRO_DEVICE_ID_JOYPAD_R,
RETRO_DEVICE_ID_JOYPAD_L2
};
for (unsigned j = 0; j < MAX_PLAYERS; j++)
{
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;
// Input data must be little endian.
input_buf[j][0] = (input_state >> 0) & 0xff;
input_buf[j][1] = (input_state >> 8) & 0xff;
}
2012-06-03 15:48:14 +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-11-20 03:28:28 +00:00
MDFNGI* curgame = (MDFNGI*)game;
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];
2014-06-20 21:11:19 +00:00
static int32_t rects[FB_MAX_HEIGHT];
rects[0] = ~0;
2012-06-03 15:48:14 +00:00
EmulateSpecStruct spec = {0};
2014-11-20 00:55:26 +00:00
spec.surface = &surf;
2012-06-03 15:48:14 +00:00
spec.SoundRate = 44100;
spec.SoundBuf = sound_buf;
spec.LineWidths = rects;
spec.SoundBufMaxSize = sizeof(sound_buf) / 2;
spec.SoundVolume = 1.0;
spec.soundmultiplier = 1.0;
spec.SoundBufSize = 0;
2013-01-19 09:22:57 +00:00
if (spec.SoundRate != last_sound_rate)
{
spec.SoundFormatChanged = true;
last_sound_rate = spec.SoundRate;
}
#ifdef PSP
#ifndef DISABLE_SW_RENDER
2014-11-20 03:28:28 +00:00
pce_do_hw_render = !input_state_cb(0, RETRO_DEVICE_JOYPAD, 0,
RETRO_DEVICE_ID_JOYPAD_X);
#endif
setting_last_scanline = 241;
#endif
2014-06-19 22:08:27 +00:00
Emulate(&spec);
2014-11-20 03:28:28 +00:00
int16* const SoundBuf = spec.SoundBuf + spec.SoundBufSizeALMS *
curgame->soundchan;
int32 SoundBufSize = spec.SoundBufSize - spec.SoundBufSizeALMS;
const int32 SoundBufMaxSize = spec.SoundBufMaxSize - spec.SoundBufSizeALMS;
2012-06-03 15:48:14 +00:00
spec.SoundBufSize = spec.SoundBufSizeALMS + SoundBufSize;
2012-06-03 15:48:14 +00:00
unsigned width = spec.DisplayRect.w & ~0x1;
2012-11-21 01:27:23 +00:00
unsigned height = spec.DisplayRect.h;
2012-10-20 21:56:43 +00:00
#ifdef PSP
#ifndef DISABLE_SW_RENDER
2014-11-20 03:28:28 +00:00
if (pce_do_hw_render)
#endif
2014-11-14 01:40:14 +00:00
video_cb(RETRO_HW_FRAME_BUFFER_VALID, width, height, 1024);
#ifndef DISABLE_SW_RENDER
else
2014-11-20 03:28:28 +00:00
// video_cb(surf->pixels16 , MEDNAFEN_CORE_GEOMETRY_BASE_W, MEDNAFEN_CORE_GEOMETRY_BASE_H, FB_WIDTH << 1);
video_cb(surf.pixels16 + surf.pitchinpix * spec.DisplayRect.y, width, height,
FB_WIDTH << 1);
#endif
#else
2014-11-20 03:28:28 +00:00
video_cb(surf.pixels16 + surf.pitchinpix * spec.DisplayRect.y, width, height,
FB_WIDTH << 1);
#endif
2012-06-03 15:48:14 +00:00
video_frames++;
audio_frames += spec.SoundBufSize;
2012-06-03 15:48:14 +00:00
audio_batch_cb(spec.SoundBuf, spec.SoundBufSize);
bool updated = false;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
check_variables();
#ifdef RUN_FOR_X_FRAMES
if (video_frames == RUN_FOR_X_FRAMES)
environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, NULL);
#endif
2012-06-03 15:48:14 +00:00
}
2014-11-20 03:28:28 +00:00
void retro_get_system_info(struct retro_system_info* info)
2012-06-03 15:48:14 +00:00
{
memset(info, 0, sizeof(*info));
info->library_name = MEDNAFEN_CORE_NAME;
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;
info->block_extract = false;
2012-06-03 15:48:14 +00:00
}
2014-11-20 03:28:28 +00:00
void retro_get_system_av_info(struct retro_system_av_info* info)
2012-06-03 15:48:14 +00:00
{
memset(info, 0, sizeof(*info));
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
}
void retro_deinit()
{
2014-11-20 00:55:26 +00:00
if (surf.pixels16)
{
free(surf.pixels16);
surf.pixels16 = NULL;
}
2013-12-17 01:24:08 +00:00
if (log_cb)
{
log_cb(RETRO_LOG_INFO, "[%s]: Samples / Frame: %.5f\n",
2014-11-20 03:28:28 +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-11-20 03:28:28 +00:00
MEDNAFEN_CORE_NAME, (double)video_frames * 44100 / audio_frames);
2013-12-17 01:24:08 +00:00
}
2014-11-19 00:31:56 +00:00
#ifdef PERF_TEST
perf_cb.perf_log();
2014-11-19 00:31:56 +00:00
#endif
#ifdef PSP
2014-11-18 22:14:37 +00:00
PSPPROF_DUMP;
#endif
}
2012-06-03 15:48:14 +00:00
unsigned retro_get_region(void)
{
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;
}
void retro_set_controller_port_device(unsigned in_port, unsigned device)
{
2014-11-20 03:28:28 +00:00
MDFNGI* currgame = (MDFNGI*)game;
if (!currgame)
2012-08-17 21:01:08 +00:00
return;
2014-11-20 03:28:28 +00:00
switch (device)
{
2014-11-20 03:28:28 +00:00
case RETRO_DEVICE_JOYPAD:
PCEINPUT_SetInput(in_port, "gamepad", &input_buf[in_port][0]);
break;
case RETRO_DEVICE_MOUSE:
PCEINPUT_SetInput(in_port, "mouse", &input_buf[in_port][0]);
break;
}
}
2012-06-03 15:48:14 +00:00
void retro_set_environment(retro_environment_t cb)
{
environ_cb = cb;
2014-11-20 03:28:28 +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" },
{ "pce_nospritelimit", "No Sprite Limit; disabled|enabled" },
{ "pce_keepaspect", "Keep Aspect; enabled|disabled" },
{ "pce_initial_scanline", "Initial scanline; 0|1|2|3|4|5|6|7|8|9|10|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40" },
2014-06-25 18:53:52 +00:00
{ "pce_last_scanline", "Last scanline; 242|241|240|239|238|237|236|235|234|232|231|230|229|228|227|226|225|224|223|222|221|220|219|218|217|216|215|214|213|212|211|210" },
{ "pce_cddavolume", "(CD) CDDA Volume; 100|90|80|70|60|50|40|30|20|10|0" },
{ "pce_adpcmvolume", "(CD) ADPCM Volume; 100|90|80|70|60|50|40|30|20|10|0" },
{ "pce_cdpsgvolume", "(CD) CD PSG Volume; 100|90|80|70|60|50|40|30|20|10|0" },
{ "pce_cdspeed", "(CD) CD Speed; 1|2|4|8" },
{ NULL, NULL },
};
2014-11-20 03:28:28 +00:00
static const struct retro_controller_description pads[] =
{
{ "PCE Joypad", RETRO_DEVICE_JOYPAD },
{ "Mouse", RETRO_DEVICE_MOUSE },
};
2014-11-20 03:28:28 +00:00
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);
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;
}
static size_t serialize_size;
2012-06-03 15:48:14 +00:00
size_t retro_serialize_size(void)
{
2014-11-20 03:28:28 +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-11-20 03:28:28 +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));
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-11-20 03:28:28 +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
}
2014-11-20 03:28:28 +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;
return MDFNSS_SaveSM(&st, 0, 0, NULL, NULL, NULL);
2012-06-03 15:48:14 +00:00
}
2014-11-20 03:28:28 +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;
return MDFNSS_LoadSM(&st, 0, 0);
2012-06-03 15:48:14 +00:00
}
2014-11-20 03:28:28 +00:00
void* retro_get_memory_data(unsigned type)
2012-06-03 15:48:14 +00:00
{
2014-11-20 03:28:28 +00:00
uint8_t* data;
2014-06-20 17:54:30 +00:00
switch (type)
{
2014-11-20 03:28:28 +00:00
case RETRO_MEMORY_SAVE_RAM:
if (IsPopulous)
data = (uint8_t*)(ROMSpace + 0x40 * 8192);
else
data = (uint8_t*)SaveRAM;
break;
default:
data = NULL;
break;
2014-06-20 17:54:30 +00:00
}
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)
{
2014-11-20 03:28:28 +00:00
case RETRO_MEMORY_SAVE_RAM:
if (IsPopulous)
size = 32768;
else
size = 2048;
break;
default:
size = 0;
break;
2014-06-20 17:54:30 +00:00
}
return size;
2012-06-03 15:48:14 +00:00
}
void retro_cheat_reset(void)
{}
2014-11-20 03:28:28 +00:00
void retro_cheat_set(unsigned, bool, const char*)
2012-06-03 15:48:14 +00:00
{}
2014-06-18 20:10:07 +00:00
2014-11-20 03:28:28 +00:00
MDFN_Thread* MDFND_CreateThread(int (*fn)(void*), void* data)
2014-06-18 20:10:07 +00:00
{
return (MDFN_Thread*)sthread_create((void (*)(void*))fn, data);
}
2014-11-20 03:28:28 +00:00
void MDFND_WaitThread(MDFN_Thread* thr, int* val)
2014-06-18 20:10:07 +00:00
{
sthread_join((sthread_t*)thr);
if (val)
{
*val = 0;
fprintf(stderr, "WaitThread relies on return value.\n");
}
}
2014-11-20 03:28:28 +00:00
void MDFND_KillThread(MDFN_Thread*)
2014-06-18 20:10:07 +00:00
{
fprintf(stderr, "Killing a thread is a BAD IDEA!\n");
}
2014-11-20 03:28:28 +00:00
MDFN_Mutex* MDFND_CreateMutex(void)
2014-06-18 20:10:07 +00:00
{
return (MDFN_Mutex*)slock_new();
}
2014-11-20 03:28:28 +00:00
void MDFND_DestroyMutex(MDFN_Mutex* lock)
2014-06-18 20:10:07 +00:00
{
slock_free((slock_t*)lock);
}
2014-11-20 03:28:28 +00:00
int MDFND_LockMutex(MDFN_Mutex* lock)
2014-06-18 20:10:07 +00:00
{
slock_lock((slock_t*)lock);
return 0;
}
2014-11-20 03:28:28 +00:00
int MDFND_UnlockMutex(MDFN_Mutex* lock)
2014-06-18 20:10:07 +00:00
{
slock_unlock((slock_t*)lock);
return 0;
}
2014-11-20 03:28:28 +00:00
MDFN_Cond* MDFND_CreateCond(void)
{
return (MDFN_Cond*)scond_new();
}
2014-11-20 03:28:28 +00:00
void MDFND_DestroyCond(MDFN_Cond* cond)
{
scond_free((scond_t*)cond);
}
2014-11-20 03:28:28 +00:00
int MDFND_WaitCond(MDFN_Cond* cond, MDFN_Mutex* mutex)
{
scond_wait((scond_t*)cond, (slock_t*)mutex);
return 0; // not sure about this return
}
2014-11-20 03:28:28 +00:00
int MDFND_SignalCond(MDFN_Cond* cond)
{
scond_signal((scond_t*)cond);
return 0; // not sure about this return
}
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.
2014-11-20 03:28:28 +00:00
std::string MDFN_MakeFName(MakeFName_Type type, int id1, const char* cd1)
2014-06-18 20:10:07 +00:00
{
char slash;
#ifdef _WIN32
slash = '\\';
#else
slash = '/';
#endif
std::string ret;
switch (type)
{
2014-11-20 03:28:28 +00:00
case MDFNMKF_SAV:
ret = retro_save_directory + slash + retro_base_name +
2014-06-18 20:10:07 +00:00
std::string(".") +
std::string(cd1);
2014-11-20 03:28:28 +00:00
break;
case MDFNMKF_FIRMWARE:
ret = retro_base_directory + slash + std::string(cd1);
2014-06-18 20:10:07 +00:00
#ifdef _WIN32
2014-11-20 03:28:28 +00:00
sanitize_path(ret); // Because Windows path handling is mongoloid.
2014-06-18 20:10:07 +00:00
#endif
2014-11-20 03:28:28 +00:00
break;
default:
break;
2014-06-18 20:10:07 +00:00
}
if (log_cb)
log_cb(RETRO_LOG_INFO, "MDFN_MakeFName: %s\n", ret.c_str());
return ret;
}
2014-11-20 03:28:28 +00:00
void MDFND_Message(const char* str)
2014-06-18 20:10:07 +00:00
{
if (log_cb)
log_cb(RETRO_LOG_INFO, "%s\n", str);
}
2014-11-20 03:28:28 +00:00
void MDFND_MidSync(const EmulateSpecStruct*)
2014-06-18 20:10:07 +00:00
{}
2014-11-20 03:28:28 +00:00
void MDFN_MidLineUpdate(EmulateSpecStruct* espec, int y)
2014-06-18 20:10:07 +00:00
{
2014-11-20 03:28:28 +00:00
//MDFND_MidLineUpdate(espec, y);
2014-06-18 20:10:07 +00:00
}
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);
}
/* forward declarations */
2014-11-20 03:28:28 +00:00
extern void MDFND_DispMessage(unsigned char* str);
2014-11-20 03:28:28 +00:00
void MDFND_DispMessage(unsigned char* str)
{
2014-11-20 03:28:28 +00:00
const char* strc = (const char*)str;
struct retro_message msg =
{
strc,
180
};
environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &msg);
}
void MDFN_ResetMessages(void)
{
}