Update to 0.9.43

This commit is contained in:
twinaphex 2017-03-27 00:35:24 +02:00
parent 4fa75e69fc
commit ca7062d75d
24 changed files with 1850 additions and 248 deletions

View File

@ -99,7 +99,11 @@ ifneq ($(HAVE_GRIFFIN), 1)
$(CORE_EMU_DIR)/smpc.cpp \
$(CORE_EMU_DIR)/input/gamepad.cpp \
$(CORE_EMU_DIR)/input/3dpad.cpp \
$(CORE_EMU_DIR)/input/mouse.cpp
$(CORE_EMU_DIR)/input/mouse.cpp \
$(CORE_EMU_DIR)/input/multitap.cpp \
$(CORE_EMU_DIR)/input/mission.cpp \
$(CORE_EMU_DIR)/input/keyboard.cpp \
$(CORE_EMU_DIR)/input/wheel.cpp
SOURCES_CXX += $(MEDNAFEN_DIR)/hw_cpu/m68k/m68k.cpp

View File

@ -30,7 +30,7 @@
#define MEDNAFEN_CORE_NAME_MODULE "ss"
#define MEDNAFEN_CORE_NAME "Mednafen Saturn"
#define MEDNAFEN_CORE_VERSION "v0.9.42"
#define MEDNAFEN_CORE_VERSION "v0.9.43"
#define MEDNAFEN_CORE_EXTENSIONS "cue|ccd"
#define MEDNAFEN_CORE_TIMING_FPS 59.82
#define MEDNAFEN_CORE_GEOMETRY_BASE_W 320
@ -121,6 +121,21 @@ void MDFN_BackupSavFile(const uint8 max_backup_count, const char* sav_ext)
#endif
}
static int64 UpdateInputLastBigTS;
static EmulateSpecStruct* espec;
static bool AllowMidSync = false;
static int32 cur_clock_div = 0;
static INLINE void UpdateSMPCInput(const sscpu_timestamp_t timestamp)
{
int32 elapsed_time = (((int64)timestamp * cur_clock_div * 1000 * 1000) - UpdateInputLastBigTS) / (EmulatedSS.MasterClock / MDFN_MASTERCLOCK_FIXED(1));
UpdateInputLastBigTS += (int64)elapsed_time * (EmulatedSS.MasterClock / MDFN_MASTERCLOCK_FIXED(1));
SMPC_UpdateInput(elapsed_time);
}
static sscpu_timestamp_t MidSync(const sscpu_timestamp_t timestamp);
#ifdef MDFN_SS_DEV_BUILD
@ -784,9 +799,6 @@ void SS_Reset(bool powering_up)
CART_Reset(powering_up);
}
static EmulateSpecStruct* espec;
static bool AllowMidSync = false;
static int32 cur_clock_div;
static sscpu_timestamp_t MidSync(const sscpu_timestamp_t timestamp)
{
if(AllowMidSync)
@ -801,12 +813,15 @@ static sscpu_timestamp_t MidSync(const sscpu_timestamp_t timestamp)
espec->MasterCycles = timestamp * cur_clock_div;
}
//printf("%d\n", espec->SoundBufSize);
SMPC_UpdateOutput();
//
//
//MDFN_MidSync(espec);
//
//
SMPC_UpdateInput();
UpdateSMPCInput(timestamp);
AllowMidSync = false;
}
@ -822,7 +837,7 @@ static void Emulate(EmulateSpecStruct* espec_arg)
MDFNGameInfo->mouse_sensitivity = MDFN_GetSettingF("ss.input.mouse_sensitivity");
cur_clock_div = SMPC_StartFrame(espec);
SMPC_UpdateInput();
UpdateSMPCInput(0);
VDP2::StartFrame(espec, cur_clock_div == 61);
espec->SoundBufSize = 0;
espec->MasterCycles = 0;
@ -853,6 +868,8 @@ static void Emulate(EmulateSpecStruct* espec_arg)
SMPC_ResetTS();
SCU_AdjustTS(-end_ts);
UpdateInputLastBigTS -= (int64)end_ts * cur_clock_div * 1000 * 1000;
if(!(SH7095_mem_timestamp & 0x40000000)) // or maybe >= 0 instead?
SH7095_mem_timestamp -= end_ts;
@ -866,6 +883,8 @@ static void Emulate(EmulateSpecStruct* espec_arg)
espec->MasterCycles = end_ts * cur_clock_div;
espec->SoundBufSize += SOUND_FlushOutput();
espec->NeedSoundReverse = false;
SMPC_UpdateOutput();
//
//
//
@ -1299,11 +1318,47 @@ static bool InitCommon(const unsigned cart_type, const unsigned smpc_area)
SOUND_Init();
InitEvents();
UpdateInputLastBigTS = 0;
#ifdef HAVE_DEBUG
DBG_Init();
#endif
#if 0
MDFN_printf("\n");
{
const bool correct_aspect = MDFN_GetSettingB("ss.correct_aspect");
const bool h_overscan = MDFN_GetSettingB("ss.h_overscan");
const bool h_blend = MDFN_GetSettingB("ss.h_blend");
MDFN_printf(_("Displayed scanlines: [%u,%u]\n"), sls, sle);
MDFN_printf(_("Correct Aspect Ratio: %s\n"), correct_aspect ? _("Enabled") : _("Disabled"));
MDFN_printf(_("Show H Overscan: %s\n"), h_overscan ? _("Enabled") : _("Disabled"));
MDFN_printf(_("H Blend: %s\n"), h_blend ? _("Enabled") : _("Disabled"));
VDP2::SetGetVideoParams(&EmulatedSS, correct_aspect, sls, sle, h_overscan, h_blend);
}
MDFN_printf("\n");
#endif
for(unsigned sp = 0; sp < 2; sp++)
{
char buf[64];
bool sv;
snprintf(buf, sizeof(buf), "ss.input.sport%u.multitap", sp + 1);
sv = MDFN_GetSettingB(buf);
SMPC_SetMultitap(sp, sv);
#if 0
MDFN_printf(_("Multitap on Saturn Port %u: %s\n"), sp + 1, sv ? _("Enabled") : _("Disabled"));
#endif
}
//
//
//
try { LoadRTC(); } catch(MDFN_Error& e) { if(e.GetErrno() != ENOENT) throw; }
try { LoadBackupRAM(); } catch(MDFN_Error& e) { if(e.GetErrno() != ENOENT) throw; }
try { LoadCartNV(); } catch(MDFN_Error& e) { if(e.GetErrno() != ENOENT) throw; }
@ -1796,8 +1851,8 @@ static const MDFNSetting_EnumList Cart_List[] =
static MDFNSetting SSSettings[] =
{
{ "ss.bios_jp", MDFNSF_EMU_STATE, "Path to the Japan ROM BIOS", "", MDFNST_STRING, "sega_101.bin" },
{ "ss.bios_na_eu", MDFNSF_EMU_STATE, "Path to the North America and Europe ROM BIOS", "", MDFNST_STRING, "mpr-17933.bin" },
{ "ss.bios_jp", MDFNSF_EMU_STATE, "Path to the Japan ROM BIOS", NULL, MDFNST_STRING, "sega_101.bin" },
{ "ss.bios_na_eu", MDFNSF_EMU_STATE, "Path to the North America and Europe ROM BIOS", NULL, MDFNST_STRING, "mpr-17933.bin" },
{ "ss.scsp.resamp_quality", MDFNSF_NOFLAGS, "SCSP output resampler quality.",
"0 is lowest quality and CPU usage, 10 is highest quality and CPU usage. The resampler that this setting refers to is used for converting from 44.1KHz to the sampling rate of the host audio device Mednafen is using. Changing Mednafen's output rate, via the \"sound.rate\" setting, to \"44100\" may bypass the resampler, which can decrease CPU usage by Mednafen, and can increase or decrease audio quality, depending on various operating system and hardware factors.", MDFNST_UINT, "4", "0", "10" },
@ -1806,6 +1861,8 @@ static MDFNSetting SSSettings[] =
{ "ss.region_default", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Default region to use.", "Used if region autodetection fails or is disabled.", MDFNST_ENUM, "jp", NULL, NULL, NULL, NULL, Region_List },
{ "ss.input.mouse_sensitivity", MDFNSF_NOFLAGS, "Emulated mouse sensitivity.", NULL, MDFNST_FLOAT, "0.50", NULL, NULL },
{ "ss.input.sport1.multitap", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Enable multitap on Saturn port 1.", NULL, MDFNST_BOOL, "0", NULL, NULL },
{ "ss.input.sport2.multitap", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Enable multitap on Saturn port 2.", NULL, MDFNST_BOOL, "0", NULL, NULL },
{ "ss.smpc.autortc", MDFNSF_NOFLAGS, "Automatically set RTC on game load.", "Automatically set the SMPC's emulated Real-Time Clock to the host system's current time and date upon game load.", MDFNST_BOOL, "1" },
{ "ss.smpc.autortc.lang", MDFNSF_NOFLAGS, "BIOS language.", NULL, MDFNST_ENUM, "english", NULL, NULL, NULL, NULL, RTCLang_List },

View File

@ -157,6 +157,13 @@ struct InputDeviceInfoStruct
const char *Description;
const IDIISG& IDII;
unsigned Flags;
enum
{
FLAG_KEYBOARD = (1U << 0)
};
};
struct InputPortInfoStruct

View File

@ -98,6 +98,9 @@ static INLINE unsigned MDFN_lzcount64_0UD(uint64 v)
#endif
}
static INLINE unsigned MDFN_lzcount64(uint64 v) { return !v ? 64 : MDFN_lzcount64_0UD(v); }
// Source: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
// Rounds up to the nearest power of 2.
static INLINE uint32 round_up_pow2(uint32 v)

View File

@ -2,7 +2,7 @@
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* 3dpad.cpp:
** Copyright (C) 2016 Mednafen Team
** Copyright (C) 2016-2017 Mednafen Team
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
@ -39,7 +39,7 @@ void IODevice_3DPad::Power(void)
data_out = 0x01;
}
void IODevice_3DPad::UpdateInput(const uint8* data)
void IODevice_3DPad::UpdateInput(const uint8* data, const int32 time_elapsed)
{
const uint16 dtmp = MDFN_de16lsb(&data[0]);

View File

@ -2,7 +2,7 @@
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* 3dpad.h:
** Copyright (C) 2016 Mednafen Team
** Copyright (C) 2016-2017 Mednafen Team
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
@ -29,7 +29,7 @@ class IODevice_3DPad final : public IODevice
virtual ~IODevice_3DPad() override;
virtual void Power(void) override;
virtual void UpdateInput(const uint8* data) override;
virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override;
virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override;
virtual uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) override;
@ -46,7 +46,6 @@ class IODevice_3DPad final : public IODevice
bool mode;
};
extern IDIISG IODevice_3DPad_IDII;
#endif

BIN
mednafen/ss/input/3dpad.o Normal file

Binary file not shown.

View File

@ -2,7 +2,7 @@
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* gamepad.cpp - Digital Gamepad Emulation
** Copyright (C) 2015-2016 Mednafen Team
** Copyright (C) 2015-2017 Mednafen Team
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
@ -37,7 +37,7 @@ void IODevice_Gamepad::Power(void)
}
void IODevice_Gamepad::UpdateInput(const uint8* data)
void IODevice_Gamepad::UpdateInput(const uint8* data, const int32 time_elapsed)
{
buttons = (~(data[0] | (data[1] << 8))) &~ 0x3000;
}

View File

@ -2,7 +2,7 @@
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* gamepad.h:
** Copyright (C) 2015-2016 Mednafen Team
** Copyright (C) 2015-2017 Mednafen Team
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
@ -29,7 +29,7 @@ class IODevice_Gamepad final : public IODevice
virtual ~IODevice_Gamepad() override;
virtual void Power(void) override;
virtual void UpdateInput(const uint8* data) override;
virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override;
virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override;
virtual uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) override;

BIN
mednafen/ss/input/gamepad.o Normal file

Binary file not shown.

View File

@ -0,0 +1,441 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* keyboard.cpp:
** Copyright (C) 2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//
// PS/2 keyboard adapter seems to do PS/2 processing near/at the end of a Saturn-side read sequence, which creates about 1 frame of extra latency
// in practice. We handle things a bit differently here, to avoid the latency.
//
// Also, the PS/2 adapter seems to set the typematic delay to around 250ms, but we emulate it here as 400ms, as 250ms is
// a tad bit too short. It can be changed to 250ms by adjusting a single #if statement, though.
//
// During testing, a couple of early-1990s PS/2 keyboards malfunctioned and failed to work with the PS/2 adapter.
// Not sure why, maybe a power draw issue?
//
// The keyboard emulated doesn't have special Windows-keyboard keys, as they don't appear to work correctly with the PS/2 adapter
// (scancode field is updated, but no make nor break bits are set to 1), and it's good to have some non-shared keys for input grabbing toggling purposes...
//
//
// make and break bits should not both be set to 1 at the same time.
// pause is special
// new key press halts repeat of held key, and it doesn't restart even if new key is released.
//
#include "common.h"
#include "keyboard.h"
#include "../math_ops.h"
IODevice_Keyboard::IODevice_Keyboard() : phys{0,0,0,0}
{
}
IODevice_Keyboard::~IODevice_Keyboard()
{
}
void IODevice_Keyboard::Power(void)
{
phase = -1;
tl = true;
data_out = 0x01;
simbutt = simbutt_pend = 0;
lock = lock_pend = 0;
mkbrk_pend = 0;
memset(buffer, 0, sizeof(buffer));
//memcpy(processed, phys, sizeof(processed));
memset(processed, 0, sizeof(processed));
memset(fifo, 0, sizeof(fifo));
fifo_rdp = 0;
fifo_wrp = 0;
fifo_cnt = 0;
rep_sc = -1;
rep_dcnt = 0;
}
void IODevice_Keyboard::UpdateInput(const uint8* data, const int32 time_elapsed)
{
phys[0] = MDFN_de64lsb(&data[0x00]);
phys[1] = MDFN_de64lsb(&data[0x08]);
phys[2] = MDFN_de16lsb(&data[0x10]);
phys[3] = 0;
//
if(rep_dcnt > 0)
rep_dcnt -= time_elapsed;
for(unsigned i = 0; i < 4; i++)
{
uint64 tmp = phys[i] ^ processed[i];
unsigned bp;
while((bp = (63 ^ MDFN_lzcount64(tmp))) < 64)
{
const uint64 mask = ((uint64)1 << bp);
const int sc = ((i << 6) + bp);
if(fifo_cnt >= (fifo_size - (sc == 0x82)))
goto fifo_oflow_abort;
if(phys[i] & mask)
{
rep_sc = sc;
#if 1
rep_dcnt = 400000;
#else
rep_dcnt = 250000;
#endif
fifo[fifo_wrp] = 0x800 | sc;
fifo_wrp = (fifo_wrp + 1) % fifo_size;
fifo_cnt++;
}
if(!(phys[i] & mask) == (sc != 0x82))
{
if(rep_sc == sc)
rep_sc = -1;
fifo[fifo_wrp] = 0x100 | sc;
fifo_wrp = (fifo_wrp + 1) % fifo_size;
fifo_cnt++;
}
processed[i] = (processed[i] & ~mask) | (phys[i] & mask);
tmp &= ~mask;
}
}
if(rep_sc >= 0)
{
while(rep_dcnt <= 0)
{
if(fifo_cnt >= fifo_size)
goto fifo_oflow_abort;
fifo[fifo_wrp] = 0x800 | rep_sc;
fifo_wrp = (fifo_wrp + 1) % fifo_size;
fifo_cnt++;
rep_dcnt += 33333;
}
}
fifo_oflow_abort:;
}
void IODevice_Keyboard::UpdateOutput(uint8* data)
{
data[0x12] = lock;
}
void IODevice_Keyboard::StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix)
{
SFORMAT StateRegs[] =
{
SFARRAY16(fifo, fifo_size),
SFVAR(fifo_rdp),
SFVAR(fifo_wrp),
SFVAR(fifo_cnt),
SFARRAY64(phys, 4),
SFARRAY64(processed, 4),
SFVAR(simbutt),
SFVAR(simbutt_pend),
SFVAR(lock),
SFVAR(lock_pend),
SFVAR(rep_sc),
SFVAR(rep_dcnt),
SFVAR(mkbrk_pend),
SFARRAY(buffer, 12),
SFVAR(data_out),
SFVAR(tl),
SFVAR(phase),
SFEND
};
char section_name[64];
snprintf(section_name, sizeof(section_name), "%s_Keyboard", sname_prefix);
if(!MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name, true) && load)
Power();
else if(load)
{
if(rep_sc >= 0 && rep_dcnt < 0)
rep_dcnt = 0;
fifo_rdp %= fifo_size;
fifo_wrp %= fifo_size;
fifo_cnt %= fifo_size + 1;
if(phase < 0)
phase = -1;
else
phase %= 12;
}
}
uint8 IODevice_Keyboard::UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted)
{
if(smpc_out & 0x40)
{
phase = -1;
tl = true;
data_out = 0x01;
}
else
{
if((bool)(smpc_out & 0x20) != tl)
{
tl = !tl;
phase += (phase < 11);
if(!phase)
{
if(mkbrk_pend == (uint8)mkbrk_pend && fifo_cnt)
{
mkbrk_pend = fifo[fifo_rdp];
fifo_rdp = (fifo_rdp + 1) % fifo_size;
fifo_cnt--;
bool p = mkbrk_pend & 0x800;
switch(mkbrk_pend & 0xFF)
{
case 0x89: /* Up */ simbutt_pend = simbutt & ~(1 << 0); simbutt_pend &= ~(p << 1); simbutt_pend |= (p << 0); break;
case 0x8A: /*Down */ simbutt_pend = simbutt & ~(1 << 1); simbutt_pend &= ~(p << 0); simbutt_pend |= (p << 1); break;
case 0x86: /*Left */ simbutt_pend = simbutt & ~(1 << 2); simbutt_pend &= ~(p << 3); simbutt_pend |= (p << 2); break;
case 0x8D: /*Right*/ simbutt_pend = simbutt & ~(1 << 3); simbutt_pend &= ~(p << 2); simbutt_pend |= (p << 3); break;
case 0x22: /* X */ simbutt_pend = simbutt & ~(1 << 4); simbutt_pend |= (p << 4); break;
case 0x21: /* C */ simbutt_pend = simbutt & ~(1 << 5); simbutt_pend |= (p << 5); break;
case 0x1A: /* Z */ simbutt_pend = simbutt & ~(1 << 6); simbutt_pend |= (p << 6); break;
case 0x76: /* Esc */ simbutt_pend = simbutt & ~(1 << 7); simbutt_pend |= (p << 7); break;
case 0x23: /* D */ simbutt_pend = simbutt & ~(1 << 8); simbutt_pend |= (p << 8); break;
case 0x1B: /* S */ simbutt_pend = simbutt & ~(1 << 9); simbutt_pend |= (p << 9); break;
case 0x1C: /* A */ simbutt_pend = simbutt & ~(1 << 10); simbutt_pend |= (p << 10); break;
case 0x24: /* E */ simbutt_pend = simbutt & ~(1 << 11); simbutt_pend |= (p << 11); break;
case 0x15: /* Q */ simbutt_pend = simbutt & ~(1 << 15); simbutt_pend |= (p << 15); break;
case 0x7E: /* Scrl */ lock_pend = lock ^ (p ? LOCK_SCROLL : 0); break;
case 0x77: /* Num */ lock_pend = lock ^ (p ? LOCK_NUM : 0); break;
case 0x58: /* Caps */ lock_pend = lock ^ (p ? LOCK_CAPS : 0); break;
}
}
buffer[ 0] = 0x3;
buffer[ 1] = 0x4;
buffer[ 2] = (((simbutt_pend >> 0) ^ 0xF) & 0xF);
buffer[ 3] = (((simbutt_pend >> 4) ^ 0xF) & 0xF);
buffer[ 4] = (((simbutt_pend >> 8) ^ 0xF) & 0xF);
buffer[ 5] = (((simbutt_pend >> 12) ^ 0xF) & 0x8) | 0x0;
buffer[ 6] = lock_pend;
buffer[ 7] = ((mkbrk_pend >> 8) & 0xF) | 0x6;
buffer[ 8] = (mkbrk_pend >> 4) & 0xF;
buffer[ 9] = (mkbrk_pend >> 0) & 0xF;
buffer[10] = 0x0;
buffer[11] = 0x1;
}
if(phase == 9)
{
mkbrk_pend = (uint8)mkbrk_pend;
lock = lock_pend;
simbutt = simbutt_pend;
}
data_out = buffer[phase];
}
}
return (smpc_out & (smpc_out_asserted | 0xE0)) | (((tl << 4) | data_out) &~ smpc_out_asserted);
}
static const IDIIS_StatusState Lock_SS[] =
{
{ "off", "Off" },
{ "on", "On" },
};
const IDIISG IODevice_Keyboard_US101_IDII =
{
/* 0x00 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x01 */ { "f9", "F9", -1, IDIT_BUTTON },
/* 0x02 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x03 */ { "f5", "F5", -1, IDIT_BUTTON },
/* 0x04 */ { "f3", "F3", -1, IDIT_BUTTON },
/* 0x05 */ { "f1", "F1", -1, IDIT_BUTTON },
/* 0x06 */ { "f2", "F2", -1, IDIT_BUTTON },
/* 0x07 */ { "f12", "F12", -1, IDIT_BUTTON },
/* 0x08 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x09 */ { "f10", "F10", -1, IDIT_BUTTON },
/* 0x0A */ { "f8", "F8", -1, IDIT_BUTTON },
/* 0x0B */ { "f6", "F6", -1, IDIT_BUTTON },
/* 0x0C */ { "f4", "F4", -1, IDIT_BUTTON },
/* 0x0D */ { "tab", "Tab", -1, IDIT_BUTTON },
/* 0x0E */ { "grave", "Grave `", -1, IDIT_BUTTON },
/* 0x0F */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x10 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x11 */ { "lalt", "Left Alt", -1, IDIT_BUTTON },
/* 0x12 */ { "lshift", "Left Shift", -1, IDIT_BUTTON },
/* 0x13 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x14 */ { "lctrl", "Left Ctrl", -1, IDIT_BUTTON },
/* 0x15 */ { "q", "Q", -1, IDIT_BUTTON },
/* 0x16 */ { "1", "1(One)", -1, IDIT_BUTTON },
/* 0x17 */ { "ralt", "Right Alt", -1, IDIT_BUTTON },
/* 0x18 */ { "rctrl", "Right Ctrl", -1, IDIT_BUTTON },
/* 0x19 */ { "kp_enter", "Keypad Enter", -1, IDIT_BUTTON },
/* 0x1A */ { "z", "Z", -1, IDIT_BUTTON },
/* 0x1B */ { "s", "S", -1, IDIT_BUTTON },
/* 0x1C */ { "a", "A", -1, IDIT_BUTTON },
/* 0x1D */ { "w", "W", -1, IDIT_BUTTON },
/* 0x1E */ { "2", "2", -1, IDIT_BUTTON },
/* 0x1F */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x20 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x21 */ { "c", "C", -1, IDIT_BUTTON },
/* 0x22 */ { "x", "X", -1, IDIT_BUTTON },
/* 0x23 */ { "d", "D", -1, IDIT_BUTTON },
/* 0x24 */ { "e", "E", -1, IDIT_BUTTON },
/* 0x25 */ { "4", "4", -1, IDIT_BUTTON },
/* 0x26 */ { "3", "3", -1, IDIT_BUTTON },
/* 0x27 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x28 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x29 */ { "space", "Space", -1, IDIT_BUTTON },
/* 0x2A */ { "v", "V", -1, IDIT_BUTTON },
/* 0x2B */ { "f", "F", -1, IDIT_BUTTON },
/* 0x2C */ { "t", "T", -1, IDIT_BUTTON },
/* 0x2D */ { "r", "R", -1, IDIT_BUTTON },
/* 0x2E */ { "5", "5", -1, IDIT_BUTTON },
/* 0x2F */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x30 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x31 */ { "n", "N", -1, IDIT_BUTTON },
/* 0x32 */ { "b", "B", -1, IDIT_BUTTON },
/* 0x33 */ { "h", "H", -1, IDIT_BUTTON },
/* 0x34 */ { "g", "G", -1, IDIT_BUTTON },
/* 0x35 */ { "y", "Y", -1, IDIT_BUTTON },
/* 0x36 */ { "6", "6", -1, IDIT_BUTTON },
/* 0x37 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x38 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x39 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x3A */ { "m", "M", -1, IDIT_BUTTON },
/* 0x3B */ { "j", "J", -1, IDIT_BUTTON },
/* 0x3C */ { "u", "U", -1, IDIT_BUTTON },
/* 0x3D */ { "7", "7", -1, IDIT_BUTTON },
/* 0x3E */ { "8", "8", -1, IDIT_BUTTON },
/* 0x3F */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x40 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x41 */ { "comma", "Comma ,", -1, IDIT_BUTTON },
/* 0x42 */ { "k", "K", -1, IDIT_BUTTON },
/* 0x43 */ { "i", "I", -1, IDIT_BUTTON },
/* 0x44 */ { "o", "O", -1, IDIT_BUTTON },
/* 0x45 */ { "0", "0(Zero)", -1, IDIT_BUTTON },
/* 0x46 */ { "9", "9", -1, IDIT_BUTTON },
/* 0x47 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x48 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x49 */ { "period", "Period .", -1, IDIT_BUTTON },
/* 0x4A */ { "slash", "Slash /", -1, IDIT_BUTTON },
/* 0x4B */ { "l", "L", -1, IDIT_BUTTON },
/* 0x4C */ { "semicolon", "Semicolon ;", -1, IDIT_BUTTON },
/* 0x4D */ { "p", "P", -1, IDIT_BUTTON },
/* 0x4E */ { "Minus", "Minus -", -1, IDIT_BUTTON },
/* 0x4F */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x50 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x51 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x52 */ { "quote", "Quote '", -1, IDIT_BUTTON },
/* 0x53 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x54 */ { "leftbracket", "Left Bracket [", -1, IDIT_BUTTON },
/* 0x55 */ { "equals", "Equals =", -1, IDIT_BUTTON },
/* 0x56 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x57 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x58 */ { "capslock", "Caps Lock", -1, IDIT_BUTTON },
/* 0x59 */ { "rshift", "Right Shift", -1, IDIT_BUTTON },
/* 0x5A */ { "enter", "Enter", -1, IDIT_BUTTON },
/* 0x5B */ { "rightbracket", "Right Bracket ]", -1, IDIT_BUTTON },
/* 0x5C */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x5D */ { "backslash", "Backslash \\", -1, IDIT_BUTTON },
/* 0x5E */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x5F */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x60 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x61 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x62 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x63 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x64 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x65 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x66 */ { "backspace", "Backspace", -1, IDIT_BUTTON },
/* 0x67 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x68 */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x69 */ { "kp_end", "Keypad End/1", -1, IDIT_BUTTON },
/* 0x6A */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x6B */ { "kp_left", "Keypad Left/4", -1, IDIT_BUTTON },
/* 0x6C */ { "kp_home", "Keypad Home/7", -1, IDIT_BUTTON },
/* 0x6D */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x6E */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x6F */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x70 */ { "kp_insert", "Keypad Insert/0", -1, IDIT_BUTTON },
/* 0x71 */ { "kp_delete", "Keypad Delete", -1, IDIT_BUTTON },
/* 0x72 */ { "kp_down", "Keypad Down/2", -1, IDIT_BUTTON },
/* 0x73 */ { "kp_center", "Keypad Center/5", -1, IDIT_BUTTON },
/* 0x74 */ { "kp_right", "Keypad Right/6", -1, IDIT_BUTTON },
/* 0x75 */ { "kp_up", "Keypad Up/8", -1, IDIT_BUTTON },
/* 0x76 */ { "esc", "Escape", -1, IDIT_BUTTON },
/* 0x77 */ { "numlock", "Num Lock", -1, IDIT_BUTTON },
/* 0x78 */ { "f11", "F11", -1, IDIT_BUTTON },
/* 0x79 */ { "kp_plus", "Keypad Plus", -1, IDIT_BUTTON },
/* 0x7A */ { "kp_pagedown", "Keypad Pagedown/3", -1, IDIT_BUTTON },
/* 0x7B */ { "kp_minus", "Keypad Minus", -1, IDIT_BUTTON },
/* 0x7C */ { "kp_asterisk", "Keypad Asterisk(Multiply)", -1, IDIT_BUTTON },
/* 0x7D */ { "kp_pageup", "Keypad Pageup/9", -1, IDIT_BUTTON },
/* 0x7E */ { "scrolllock", "Scroll Lock", -1, IDIT_BUTTON },
/* 0x7F */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x80 */ { "kp_slash", "Keypad Slash(Divide)", -1, IDIT_BUTTON },
/* 0x81 */ { "insert", "Insert", -1, IDIT_BUTTON },
/* 0x82 */ { "pause", "Pause", -1, IDIT_BUTTON },
/* 0x83 */ { "f7", "F7", -1, IDIT_BUTTON },
/* 0x84 */ { "printscreen", "Print Screen", -1, IDIT_BUTTON },
/* 0x85 */ { "delete", "Delete", -1, IDIT_BUTTON },
/* 0x86 */ { "left", "Cursor Left", -1, IDIT_BUTTON },
/* 0x87 */ { "home", "Home", -1, IDIT_BUTTON },
/* 0x88 */ { "end", "End", -1, IDIT_BUTTON },
/* 0x89 */ { "up", "Up", -1, IDIT_BUTTON },
/* 0x8A */ { "down", "Down", -1, IDIT_BUTTON },
/* 0x8B */ { "pageup", "Page Up", -1, IDIT_BUTTON },
/* 0x8C */ { "pagedown", "Page Down", -1, IDIT_BUTTON },
/* 0x8D */ { "right", "Right", -1, IDIT_BUTTON },
/* 0x8E */ { NULL, "empty", -1, IDIT_BUTTON },
/* 0x8F */ { NULL, "empty", -1, IDIT_BUTTON },
IDIIS_Status("scrolllock_status", "Scroll Lock", Lock_SS, sizeof(Lock_SS) / sizeof(Lock_SS[0])),
IDIIS_Status("numlock_status", "Num Lock", Lock_SS, sizeof(Lock_SS) / sizeof(Lock_SS[0])),
IDIIS_Status("capslock_status", "Caps Lock", Lock_SS, sizeof(Lock_SS) / sizeof(Lock_SS[0]))
};

View File

@ -0,0 +1,70 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* keyboard.h:
** Copyright (C) 2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MDFN_SS_INPUT_KEYBOARD_H
#define __MDFN_SS_INPUT_KEYBOARD_H
class IODevice_Keyboard final : public IODevice
{
public:
IODevice_Keyboard();
virtual ~IODevice_Keyboard() override;
virtual void Power(void) override;
virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override;
virtual void UpdateOutput(uint8* data) override;
virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override;
virtual uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) override;
private:
uint64 phys[4];
uint64 processed[4];
uint8 lock;
uint8 lock_pend;
uint16 simbutt;
uint16 simbutt_pend;
enum { fifo_size = 16 };
uint16 fifo[fifo_size];
uint8 fifo_rdp;
uint8 fifo_wrp;
uint8 fifo_cnt;
enum
{
LOCK_SCROLL = 0x01,
LOCK_NUM = 0x02,
LOCK_CAPS = 0x04
};
int16 rep_sc;
int32 rep_dcnt;
int16 mkbrk_pend;
uint8 buffer[12];
uint8 data_out;
bool tl;
int8 phase;
};
extern const IDIISG IODevice_Keyboard_US101_IDII;
#endif

View File

@ -0,0 +1,359 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* mission.cpp:
** Copyright (C) 2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
Real mission stick has bugs and quirks that aren't emulated here(like apparently latching/updating the physical input state at the end of the
read sequence instead of near the beginning like other controllers do, resulting in increased latency).
*/
#include "common.h"
#include "mission.h"
IODevice_Mission::IODevice_Mission(const bool dual_) : dbuttons(0), afeswitches(0), afspeed(0), dual(dual_)
{
}
IODevice_Mission::~IODevice_Mission()
{
}
void IODevice_Mission::Power(void)
{
phase = -1;
tl = true;
data_out = 0x01;
// Power-on state not tested:
afcounter = 0;
afphase = false;
}
void IODevice_Mission::UpdateInput(const uint8* data, const int32 time_elapsed)
{
const uint32 dtmp = MDFN_de32lsb(&data[0]);
dbuttons = (dbuttons & 0xF) | ((dtmp & 0xFFF) << 4);
afeswitches = ((dtmp >> 12) & 0x8FF) << 4;
afspeed = (dtmp >> 20) & 0x7;
for(unsigned stick = 0; stick < (dual ? 2 : 1); stick++)
{
for(unsigned axis = 0; axis < 3; axis++)
{
int32 tmp = 32767 + MDFN_de16lsb(&data[0x3 + ((axis + (stick * 3)) * 4) + 2]) - MDFN_de16lsb(&data[0x3 + ((axis + (stick * 3)) * 4) + 0]);
axes[stick][axis] = (tmp * 255 + 32767) / 65534;
}
}
//printf("Update: %02x %02x %02x\n", axes[0][0], axes[0][1], axes[0][2]);
}
void IODevice_Mission::StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix)
{
SFORMAT StateRegs[] =
{
SFVAR(dbuttons),
SFVAR(afeswitches),
SFVAR(afspeed),
SFVAR(afcounter),
SFVAR(afphase),
SFARRAY(&axes[0][0], 2 * 3),
SFARRAY(buffer, 0x20),
SFVAR(data_out),
SFVAR(tl),
SFVAR(phase),
SFEND
};
char section_name[64];
snprintf(section_name, sizeof(section_name), "%s_Mission", sname_prefix);
if(!MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name, true) && load)
Power();
else if(load)
{
afspeed %= 7;
if(phase < 0)
phase = -1;
else
phase &= 0x1F;
}
}
uint8 IODevice_Mission::UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted)
{
uint8 tmp;
if(smpc_out & 0x40)
{
phase = -1;
tl = true;
data_out = 0x01;
}
else
{
if((bool)(smpc_out & 0x20) != tl)
{
if(phase < (dual ? 21 : 13))
{
tl = !tl;
phase++;
}
if(!phase)
{
unsigned dbaf = dbuttons & ((afphase - 1) | ~afeswitches);
unsigned c = 0;
// Digital Left
dbuttons |= ((axes[0][0] <= 0x56) ? 0x4 : 0);
dbuttons &= ~((axes[0][0] >= 0x6C) ? 0x4 : 0);
// Digital Right
dbuttons |= ((axes[0][0] >= 0xAB) ? 0x8 : 0);
dbuttons &= ~((axes[0][0] <= 0x95) ? 0x8 : 0);
// Digital Up
dbuttons |= ((axes[0][1] <= 0x54) ? 0x1 : 0);
dbuttons &= ~((axes[0][1] >= 0x6A) ? 0x1 : 0);
// Digital Down
dbuttons |= ((axes[0][1] >= 0xA9) ? 0x2 : 0);
dbuttons &= ~((axes[0][1] <= 0x94) ? 0x2 : 0);
if(!afcounter)
{
static const uint8 speedtab[7] = { 12, 8, 7, 5, 4, 4/* ? */, 1 };
afphase = !afphase;
afcounter = speedtab[afspeed];
}
afcounter--;
buffer[c++] = 0x1;
buffer[c++] = dual ? 0x9 : 0x5;
buffer[c++] = (((dbaf >> 0) & 0xF) ^ 0xF);
buffer[c++] = (((dbaf >> 4) & 0xF) ^ 0xF);
buffer[c++] = (((dbaf >> 8) & 0xF) ^ 0xF);
buffer[c++] = (((dbaf >> 12) & 0xF) ^ 0xF);
for(unsigned stick = 0; stick < (dual ? 2 : 1); stick++)
{
if(stick)
{
// Not sure, looks like something buggy.
buffer[c++] = 0x0;
buffer[c++] = 0x0;
}
buffer[c++] = (axes[stick][0] >> 4) & 0xF;
buffer[c++] = (axes[stick][0] >> 0) & 0xF;
buffer[c++] = (axes[stick][1] >> 4) & 0xF;
buffer[c++] = (axes[stick][1] >> 0) & 0xF;
buffer[c++] = (axes[stick][2] >> 4) & 0xF;
buffer[c++] = (axes[stick][2] >> 0) & 0xF;
}
buffer[c++] = 0x0;
buffer[c++] = 0x1;
}
data_out = buffer[phase];
}
}
tmp = (tl << 4) | data_out;
return (smpc_out & (smpc_out_asserted | 0xE0)) | (tmp &~ smpc_out_asserted);
}
static const char* SpeedSwitchPositions[] =
{
"1/7",
"2/7",
"3/7",
"4/7",
"5/7",
"6/7",
"7/7"
};
static const char* AFSwitchPositions[] =
{
"• (Off)",
"•• (On))"
};
IDIISG IODevice_Mission_IDII =
{
// 0
{ "b", "B (Stick Left Button)", 6, IDIT_BUTTON },
{ "c", "C (Stick Right Button)", 8, IDIT_BUTTON },
{ "a", "A (Stick Trigger)", 7, IDIT_BUTTON },
{ "start", "START", 9, IDIT_BUTTON },
// 4
{ "z", "Z", 13, IDIT_BUTTON },
{ "y", "Y", 12, IDIT_BUTTON },
{ "x", "X", 11, IDIT_BUTTON },
{ "r", "R", 14, IDIT_BUTTON },
// 8
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ "l", "L", 10, IDIT_BUTTON },
// 12
IDIIS_Switch("afb", "B AF", 20, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
IDIIS_Switch("afc", "C AF", 21, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
IDIIS_Switch("afa", "A AF", 19, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
{ NULL, "empty", 0, IDIT_BUTTON },
// 16
IDIIS_Switch("afz", "Z AF", 17, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
IDIIS_Switch("afy", "Y AF", 16, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
IDIIS_Switch("afx", "X AF", 15, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
IDIIS_Switch("afr", "R AF", 22, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
// 20
IDIIS_Switch("afspeed", "AF Speed", 23, SpeedSwitchPositions, sizeof(SpeedSwitchPositions) / sizeof(SpeedSwitchPositions[0])),
IDIIS_Switch("afl", "L AF", 18, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
// 24
{ "stick_left", "Stick LEFT ← (Analog)", 2, IDIT_BUTTON_ANALOG },
{ "stick_right", "Stick RIGHT → (Analog)", 3, IDIT_BUTTON_ANALOG },
{ "stick_fore", "Stick FORE ↑ (Analog)", 0, IDIT_BUTTON_ANALOG },
{ "stick_back", "Stick BACK ↓ (Analog)", 1, IDIT_BUTTON_ANALOG },
{ "throttle_down", "Throttle Down (Analog)", 5, IDIT_BUTTON_ANALOG },
{ "throttle_up", "Throttle Up (Analog)", 4, IDIT_BUTTON_ANALOG },
};
IDIISG IODevice_MissionNoAF_IDII =
{
// 0
{ "b", "B (Stick Left Button)", 6, IDIT_BUTTON },
{ "c", "C (Stick Right Button)", 8, IDIT_BUTTON },
{ "a", "A (Stick Trigger)", 7, IDIT_BUTTON },
{ "start", "START", 9, IDIT_BUTTON },
// 4
{ "z", "Z", 13, IDIT_BUTTON },
{ "y", "Y", 12, IDIT_BUTTON },
{ "x", "X", 11, IDIT_BUTTON },
{ "r", "R", 14, IDIT_BUTTON },
// 8
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ "l", "L", 10, IDIT_BUTTON },
// 12
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// 16
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// 20
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
// 24
{ "stick_left", "Stick LEFT ← (Analog)", 2, IDIT_BUTTON_ANALOG },
{ "stick_right", "Stick RIGHT → (Analog)", 3, IDIT_BUTTON_ANALOG },
{ "stick_fore", "Stick FORE ↑ (Analog)", 0, IDIT_BUTTON_ANALOG },
{ "stick_back", "Stick BACK ↓ (Analog)", 1, IDIT_BUTTON_ANALOG },
{ "throttle_down", "Throttle Down (Analog)", 5, IDIT_BUTTON_ANALOG },
{ "throttle_up", "Throttle Up (Analog)", 4, IDIT_BUTTON_ANALOG },
};
IDIISG IODevice_DualMission_IDII =
{
// 0
{ "b", "B (R Stick Left Button)", 15, IDIT_BUTTON },
{ "c", "C (R Stick Right Button)", 17, IDIT_BUTTON },
{ "a", "A (R Stick Trigger)", 16, IDIT_BUTTON },
{ "start", "START", 18, IDIT_BUTTON },
// 4
{ "z", "Z (L Stick Right Button)", 8, IDIT_BUTTON },
{ "y", "Y (L Stick Left Button)", 6, IDIT_BUTTON },
{ "x", "X (L Stick Trigger)", 7, IDIT_BUTTON },
{ "r", "R", 20, IDIT_BUTTON },
// 8
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ "l", "L", 19, IDIT_BUTTON },
// 12
IDIIS_Switch("afb", "B AF", 26, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
IDIIS_Switch("afc", "C AF", 27, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
IDIIS_Switch("afa", "A AF", 25, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
{ NULL, "empty", 0, IDIT_BUTTON },
// 16
IDIIS_Switch("afz", "Z AF", 23, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
IDIIS_Switch("afy", "Y AF", 22, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
IDIIS_Switch("afx", "X AF", 21, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
IDIIS_Switch("afr", "R AF", 28, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
// 20
IDIIS_Switch("afspeed", "Autofire Speed", 29, SpeedSwitchPositions, sizeof(SpeedSwitchPositions) / sizeof(SpeedSwitchPositions[0])),
IDIIS_Switch("afl", "L AF", 24, AFSwitchPositions, sizeof(AFSwitchPositions) / sizeof(AFSwitchPositions[0])),
// 24
{ "rstick_left", "R Stick LEFT ← (Analog)", 11, IDIT_BUTTON_ANALOG },
{ "rstick_right", "R Stick RIGHT → (Analog)", 12, IDIT_BUTTON_ANALOG },
{ "rstick_fore", "R Stick FORE ↑ (Analog)", 9, IDIT_BUTTON_ANALOG },
{ "rstick_back", "R Stick BACK ↓ (Analog)", 10, IDIT_BUTTON_ANALOG },
{ "rthrottle_down", "R Throttle Down (Analog)", 14, IDIT_BUTTON_ANALOG },
{ "rthrottle_up", "R Throttle Up (Analog)", 13, IDIT_BUTTON_ANALOG },
{ "lstick_left", "L Stick LEFT ← (Analog)", 2, IDIT_BUTTON_ANALOG },
{ "lstick_right", "L Stick RIGHT → (Analog)", 3, IDIT_BUTTON_ANALOG },
{ "lstick_fore", "L Stick FORE ↑ (Analog)", 0, IDIT_BUTTON_ANALOG },
{ "lstick_back", "L Stick BACK ↓ (Analog)", 1, IDIT_BUTTON_ANALOG },
{ "lthrottle_down", "L Throttle Down (Analog)", 5, IDIT_BUTTON_ANALOG },
{ "lthrottle_up", "L Throttle Up (Analog)", 4, IDIT_BUTTON_ANALOG },
};

View File

@ -0,0 +1,60 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* mission.h:
** Copyright (C) 2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MDFN_SS_INPUT_MISSION_H
#define __MDFN_SS_INPUT_MISSION_H
class IODevice_Mission final : public IODevice
{
public:
IODevice_Mission(const bool dual_);
virtual ~IODevice_Mission() override;
virtual void Power(void) override;
virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override;
virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override;
virtual uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) override;
private:
uint16 dbuttons;
uint16 afeswitches;
uint8 afspeed;
uint8 axes[2][3];
uint8 buffer[0x20];
uint8 data_out;
bool tl;
int8 phase;
uint8 afcounter;
bool afphase;
const bool dual;
};
extern IDIISG IODevice_Mission_IDII;
extern IDIISG IODevice_MissionNoAF_IDII;
extern IDIISG IODevice_DualMission_IDII;
#endif

View File

@ -2,7 +2,7 @@
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* mouse.cpp:
** Copyright (C) 2016 Mednafen Team
** Copyright (C) 2016-2017 Mednafen Team
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
@ -41,7 +41,7 @@ void IODevice_Mouse::Power(void)
accum_ydelta = 0;
}
void IODevice_Mouse::UpdateInput(const uint8* data)
void IODevice_Mouse::UpdateInput(const uint8* data, const int32 time_elapsed)
{
accum_xdelta += MDFN_de32lsb(&data[0]);
accum_ydelta -= MDFN_de32lsb(&data[4]);

View File

@ -2,7 +2,7 @@
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* mouse.h:
** Copyright (C) 2016 Mednafen Team
** Copyright (C) 2016-2017 Mednafen Team
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
@ -29,7 +29,7 @@ class IODevice_Mouse final : public IODevice
virtual ~IODevice_Mouse() override;
virtual void Power(void) override;
virtual void UpdateInput(const uint8* data) override;
virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override;
virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override;
virtual uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) override;

BIN
mednafen/ss/input/mouse.o Normal file

Binary file not shown.

View File

@ -0,0 +1,239 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* multitap.cpp:
** Copyright (C) 2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "common.h"
#include "multitap.h"
IODevice_Multitap::IODevice_Multitap()
{
}
IODevice_Multitap::~IODevice_Multitap()
{
}
void IODevice_Multitap::Power(void)
{
phase = -2;
tl = true;
data_out = 0x01;
memset(tmp, 0x00, sizeof(tmp));
id1 = 0;
id2 = 0;
port_counter = 0;
read_counter = 0;
for(unsigned i = 0; i < 6; i++)
{
if(devices[i])
{
sub_state[i] = 0x60;
devices[i]->UpdateBus(sub_state[i], 0x60);
devices[i]->Power();
}
}
}
void IODevice_Multitap::SetSubDevice(unsigned sub_index, IODevice* device)
{
assert(sub_index < 6);
devices[sub_index] = device;
devices[sub_index]->UpdateBus(sub_state[sub_index], 0x60);
}
IODevice* IODevice_Multitap::GetSubDevice(unsigned sub_index)
{
assert(sub_index < 6);
return devices[sub_index];
}
void IODevice_Multitap::StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix)
{
SFORMAT StateRegs[] =
{
SFARRAY(sub_state, 6),
SFARRAY(tmp, 4),
SFVAR(id1),
SFVAR(id2),
SFVAR(data_out),
SFVAR(tl),
SFVAR(phase),
SFVAR(port_counter),
SFVAR(read_counter),
SFEND
};
char section_name[32];
snprintf(section_name, sizeof(section_name), "%s_Multitap", sname_prefix);
if(!MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name, true) && load)
Power();
else if(load)
{
port_counter %= 6;
}
for(unsigned i = 0; i < 6; i++)
{
char snsp[32];
snprintf(snsp, sizeof(snsp), "%sP%u", section_name, i);
devices[i]->StateAction(sm, load, data_only, snsp);
}
}
enum { PhaseBias = __COUNTER__ + 1 };
#define WAIT_UNTIL(cond) { \
case __COUNTER__: \
if(!(cond)) \
{ \
phase = __COUNTER__ - PhaseBias - 1; \
goto BreakOut; \
} \
}
#define WR_NYB(v) { WAIT_UNTIL((bool)(smpc_out & 0x20) != tl); data_out = (v) & 0xF; tl = !tl; }
INLINE uint8 IODevice_Multitap::UASB(void)
{
return devices[port_counter]->UpdateBus(sub_state[port_counter], 0x60);
}
uint8 IODevice_Multitap::UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted)
{
if(smpc_out & 0x40)
{
phase = -1;
tl = true;
data_out = 0x01;
}
else
{
switch(phase + PhaseBias)
{
for(;;)
{
default:
case __COUNTER__:
WAIT_UNTIL(phase == -1);
WR_NYB(0x4);
WR_NYB(0x1);
WR_NYB(0x6);
WR_NYB(0x0);
//
//
port_counter = 0;
do
{
sub_state[port_counter] = 0x60;
UASB();
// ...
tmp[0] = UASB();
id1 = ((((tmp[0] >> 3) | (tmp[0] >> 2)) & 1) << 3) | ((((tmp[0] >> 1) | (tmp[0] >> 0)) & 1) << 2);
sub_state[port_counter] = 0x20;
UASB();
// ...
tmp[1] = UASB();
id1 |= ((((tmp[1] >> 3) | (tmp[1] >> 2)) & 1) << 1) | ((((tmp[1] >> 1) | (tmp[1] >> 0)) & 1) << 0);
//printf("%d, %01x\n", port_counter, id1);
if(id1 == 0xB) // Digital pad
{
WR_NYB(0x0);
WR_NYB(0x2);
sub_state[port_counter] = 0x40;
UASB();
WR_NYB(tmp[1] & 0xF);
tmp[2] = UASB();
sub_state[port_counter] = 0x00;
UASB();
WR_NYB(tmp[2] & 0xF);
tmp[3] = UASB();
WR_NYB(tmp[3] & 0xF);
WR_NYB((tmp[0] & 0xF) | 0x7);
}
else if(id1 == 0x3 || id1 == 0x5) // Analog
{
sub_state[port_counter] = 0x00;
WAIT_UNTIL(!(UASB() & 0x10));
id2 = ((UASB() & 0xF) << 4);
sub_state[port_counter] = 0x20;
WAIT_UNTIL(UASB() & 0x10);
id2 |= ((UASB() & 0xF) << 0);
if(id1 == 0x3)
id2 = 0xE3;
WR_NYB(id2 >> 4);
WR_NYB(id2 >> 0);
read_counter = 0;
while(read_counter < (id2 & 0xF))
{
sub_state[port_counter] = 0x00;
WAIT_UNTIL(!(UASB() & 0x10));
WR_NYB(UASB() & 0xF);
sub_state[port_counter] = 0x20;
WAIT_UNTIL(UASB() & 0x10);
WR_NYB(UASB() & 0xF);
read_counter++;
}
}
else
{
WR_NYB(0xF);
WR_NYB(0xF);
}
sub_state[port_counter] = 0x60;
UASB();
} while(++port_counter < 6);
//
//
WR_NYB(0x0);
WR_NYB(0x1);
}
}
}
BreakOut:;
return (smpc_out & (smpc_out_asserted | 0xE0)) | (((tl << 4) | data_out) &~ smpc_out_asserted);
}

View File

@ -0,0 +1,55 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* multitap.h:
** Copyright (C) 2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MDFN_SS_INPUT_MULTITAP_H
#define __MDFN_SS_INPUT_MULTITAP_H
class IODevice_Multitap final : public IODevice
{
public:
IODevice_Multitap();
virtual ~IODevice_Multitap() override;
virtual void Power(void) override;
virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override;
virtual uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) override;
void SetSubDevice(unsigned sub_index, IODevice* device);
IODevice* GetSubDevice(unsigned sub_index);
private:
uint8 UASB(void);
IODevice* devices[6];
uint8 sub_state[6];
uint8 tmp[4];
uint8 id1;
uint8 id2;
uint8 data_out;
bool tl;
int32 phase;
uint8 port_counter;
uint8 read_counter;
};
#endif

161
mednafen/ss/input/wheel.cpp Normal file
View File

@ -0,0 +1,161 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* wheel.cpp:
** Copyright (C) 2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "common.h"
#include "wheel.h"
IODevice_Wheel::IODevice_Wheel() : dbuttons(0)
{
}
IODevice_Wheel::~IODevice_Wheel()
{
}
void IODevice_Wheel::Power(void)
{
phase = -1;
tl = true;
data_out = 0x01;
}
void IODevice_Wheel::UpdateInput(const uint8* data, const int32 time_elapsed)
{
dbuttons = (dbuttons & 0xC) | (MDFN_de16lsb(&data[0]) & 0x07F3);
//
{
int32 tmp = 32767 + MDFN_de16lsb(&data[0x2 + 2]) - MDFN_de16lsb(&data[0x2 + 0]);
wheel = 1 + tmp * 253 / 65534;
if(wheel >= 0x6F)
dbuttons &= ~0x4;
else if(wheel <= 0x67)
dbuttons |= 0x4;
if(wheel <= 0x8F)
dbuttons &= ~0x8;
else if(wheel >= 0x97)
dbuttons |= 0x8;
}
}
void IODevice_Wheel::StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix)
{
SFORMAT StateRegs[] =
{
SFVAR(dbuttons),
SFVAR(wheel),
SFARRAY(buffer, 0x10),
SFVAR(data_out),
SFVAR(tl),
SFVAR(phase),
SFEND
};
char section_name[64];
snprintf(section_name, sizeof(section_name), "%s_Wheel", sname_prefix);
if(!MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name, true) && load)
Power();
else if(load)
{
if(phase < 0)
phase = -1;
else
phase &= 0xF;
}
}
uint8 IODevice_Wheel::UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted)
{
uint8 tmp;
if(smpc_out & 0x40)
{
phase = -1;
tl = true;
data_out = 0x01;
}
else
{
if((bool)(smpc_out & 0x20) != tl)
{
if(phase < 0)
{
buffer[ 0] = 0x1;
buffer[ 1] = 0x3;
buffer[ 2] = (((dbuttons >> 0) & 0xF) ^ 0xF);
buffer[ 3] = (((dbuttons >> 4) & 0xF) ^ 0xF);
buffer[ 4] = (((dbuttons >> 8) & 0xF) ^ 0xF);
buffer[ 5] = (((dbuttons >> 12) & 0xF) ^ 0xF);
buffer[ 6] = ((wheel >> 4) & 0xF);
buffer[ 7] = ((wheel >> 0) & 0xF);
buffer[ 8] = 0x0;
buffer[ 9] = 0x1;
buffer[10] = 0x1;
buffer[11] = ((wheel >> 0) & 0xF);
buffer[12] = 0x0;
buffer[13] = 0x1;
buffer[14] = 0x1;
buffer[15] = 0x1;
}
phase = (phase + 1) & 0xF;
data_out = buffer[phase];
tl = !tl;
}
}
tmp = (tl << 4) | data_out;
return (smpc_out & (smpc_out_asserted | 0xE0)) | (tmp &~ smpc_out_asserted);
}
IDIISG IODevice_Wheel_IDII =
{
{ "up", "L Gear Shift(Equiv. UP ↑)", 2, IDIT_BUTTON, "down" },
{ "down", "R Gear Shift(Equiv. DOWN ↓)", 3, IDIT_BUTTON, "up" },
{ NULL, "empty", 0, IDIT_BUTTON }, // left
{ NULL, "empty", 0, IDIT_BUTTON }, // right
{ "b", "B (R Group)", 9, IDIT_BUTTON },
{ "c", "C (R Group)", 10, IDIT_BUTTON },
{ "a", "A (R Group)", 8, IDIT_BUTTON },
{ "start", "START", 7, IDIT_BUTTON },
{ "z", "Z (L Group)", 4, IDIT_BUTTON },
{ "y", "Y (L Group)", 5, IDIT_BUTTON },
{ "x", "X (L Group)", 6, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ NULL, "empty", 0, IDIT_BUTTON },
{ "analog_left", "Analog LEFT ←", 0, IDIT_BUTTON_ANALOG },
{ "analog_right", "Analog RIGHT →", 1, IDIT_BUTTON_ANALOG },
};

50
mednafen/ss/input/wheel.h Normal file
View File

@ -0,0 +1,50 @@
/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* wheel.h:
** Copyright (C) 2017 Mednafen Team
**
** 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.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MDFN_SS_INPUT_WHEEL_H
#define __MDFN_SS_INPUT_WHEEL_H
class IODevice_Wheel final : public IODevice
{
public:
IODevice_Wheel();
virtual ~IODevice_Wheel() override;
virtual void Power(void) override;
virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override;
virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) override;
virtual uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) override;
private:
uint16 dbuttons;
uint8 wheel;
uint8 buffer[0x10];
uint8 data_out;
bool tl;
int8 phase;
};
extern IDIISG IODevice_Wheel_IDII;
#endif

View File

@ -178,94 +178,3 @@ Funky Fantasy:
[SCU] Starting DMA level 1 transfer; ra=0x00000000 wa=0x05c00060 bc=0x0000001e - read_inc=1, write_inc=0x01 -- indirect=1 7
[SCU] Attempted DMA from illegal address 0x00000000
-----------------------------------------------------
Magic Knight Rayearth
sh2 read 25A00481 25A00482
Working path:
[M68K] Exception 9(vec=26) @PC=0x00001178 SR=0x2000 ---> PC=0x00001368, SR=0x2200
[M68K] Exception 9(vec=26) @PC=0x000011cc SR=0x2000 ---> PC=0x00001368, SR=0x2200
[M68K] Exception 9(vec=26) @PC=0x00001178 SR=0x2000 ---> PC=0x00001368, SR=0x2200
16-bit: 00000782 100
8-bit: 00000702 01
8-bit: 00000703 00
8-bit: 00000704 00
8-bit: 00000705 01
16-bit: 00000700 100
[M68K] Exception 9(vec=26) @PC=0x00004fb0 SR=0x2000 ---> PC=0x00001368, SR=0x2200
[M68K] Exception 9(vec=26) @PC=0x0000117a SR=0x2004 ---> PC=0x00001368, SR=0x2204
[M68K] Exception 9(vec=26) @PC=0x00001072 SR=0x2000 ---> PC=0x00001368, SR=0x2200
(...)
[M68K] Exception 9(vec=26) @PC=0x00001142 SR=0x2000 ---> PC=0x00001368, SR=0x2200
[M68K] Exception 9(vec=26) @PC=0x0000112e SR=0x2000 ---> PC=0x00001368, SR=0x2200
8-bit: 00000702 06
8-bit: 00000703 e0
8-bit: 00000704 78
8-bit: 00000705 00
8-bit: 00000706 10
8-bit: 00000707 10
16-bit: 00000700 8a00
[M68K] Exception 9(vec=26) @PC=0x000030ca SR=0x2004 ---> PC=0x00001368, SR=0x2204
[M68K] Exception 9(vec=26) @PC=0x000030ce SR=0x2000 ---> PC=0x00001368, SR=0x2200
[M68K] Exception 9(vec=26) @PC=0x0000108e SR=0x2000 ---> PC=0x00001368, SR=0x2200
16-bit: 0010042e 20
[M68K] Exception 9(vec=26) @PC=0x000011cc SR=0x2000 ---> PC=0x00001368, SR=0x2200
[M68K] Exception 9(vec=26) @PC=0x000011c8 SR=0x2004 ---> PC=0x00001368, SR=0x2204
[M68K] Exception 9(vec=26) @PC=0x00001176 SR=0x2000 ---> PC=0x00001368, SR=0x2200
[M68K] Exception 9(vec=26) @PC=0x00001176 SR=0x2000 ---> PC=0x00001368, SR=0x2200
[M68K] Exception 9(vec=26) @PC=0x0000107e SR=0x2000 ---> PC=0x00001368, SR=0x2200
[M68K] Exception 9(vec=26) @PC=0x0000107a SR=0x2000 ---> PC=0x00001368, SR=0x2200
16-bit: 0010042e 20
16-bit: 0007e000 00
16-bit: 0007e002 00
16-bit: 0007e004 00
16-bit: 0007e006 00
16-bit: 0007e008 00
16-bit: 0007e00a 00
16-bit: 0007e00c 00
16-bit: 0007e00e 00
16-bit: 0007e010 00
16-bit: 0007e012 00
16-bit: 0007e014 00
(...and so on with the apparent PCM data)
***Broken path***:
16-bit: 0010042e 20
[M68K] Exception 9(vec=26) @PC=0x000011c8 SR=0x2004 ---> PC=0x00001368, SR=0x2204
[M68K] Exception 9(vec=26) @PC=0x000011c8 SR=0x2004 ---> PC=0x00001368, SR=0x2204
[M68K] Exception 9(vec=26) @PC=0x000011c8 SR=0x2004 ---> PC=0x00001368, SR=0x2204
[M68K] Exception 9(vec=26) @PC=0x000011cc SR=0x200a ---> PC=0x00001368, SR=0x220a
[M68K] Exception 9(vec=26) @PC=0x000011c8 SR=0x2004 ---> PC=0x00001368, SR=0x2204
16-bit: 00000782 100
8-bit: 00000702 01
8-bit: 00000703 00
8-bit: 00000704 00
8-bit: 00000705 01
16-bit: 00000700 100
[M68K] Exception 9(vec=26) @PC=0x00001172 SR=0x2004 ---> PC=0x00001368, SR=0x2204
[M68K] Exception 9(vec=26) @PC=0x0000108a SR=0x200a ---> PC=0x00001368, SR=0x220a
[M68K] Exception 9(vec=26) @PC=0x00001076 SR=0x2004 ---> PC=0x00001368, SR=0x2204
16-bit: 0010042e 20
(...)
16-bit: 0010042e 20
[M68K] Exception 9(vec=26) @PC=0x000030ba SR=0x2000 ---> PC=0x00001368, SR=0x2200
[M68K] Exception 9(vec=26) @PC=0x0000112c SR=0x2004 ---> PC=0x00001368, SR=0x2204
[M68K] Exception 9(vec=26) @PC=0x00001134 SR=0x2004 ---> PC=0x00001368, SR=0x2204
[M68K] Exception 9(vec=26) @PC=0x000030a8 SR=0x2000 ---> PC=0x00001368, SR=0x2200
[M68K] Exception 9(vec=26) @PC=0x00001136 SR=0x2000 ---> PC=0x00001368, SR=0x2200
8-bit: 00000702 06
8-bit: 00000703 e0
8-bit: 00000704 78
8-bit: 00000705 00
8-bit: 00000706 10
8-bit: 00000707 10
16-bit: 00000700 8a00
[M68K] Exception 9(vec=26) @PC=0x00003090 SR=0x2000 ---> PC=0x00001368, SR=0x2200
[M68K] Exception 9(vec=26) @PC=0x00001162 SR=0x2000 ---> PC=0x00001368, SR=0x2200
[M68K] Exception 9(vec=26) @PC=0x000030c2 SR=0x2000 ---> PC=0x00001368, SR=0x2200
16-bit: 0010042e 20

View File

@ -2,7 +2,7 @@
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* smpc.cpp - SMPC Emulation
** Copyright (C) 2015-2016 Mednafen Team
** Copyright (C) 2015-2017 Mednafen Team
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
@ -19,7 +19,10 @@
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// TODO: CD On/Off
/*
TODO:
CD On/Off
*/
#include "ss.h"
#include <mednafen/mednafen.h>
@ -37,8 +40,12 @@
#include "input/gamepad.h"
#include "input/3dpad.h"
#include "input/mouse.h"
#include "input/wheel.h"
#include "input/mission.h"
#include "input/keyboard.h"
#include <time.h>
#include "input/multitap.h"
#include "sh7095.h"
@ -128,6 +135,7 @@ static bool ResetButtonPhysStatus;
static int32 ResetButtonCount;
static bool ResetPending;
static int32 PendingCommand;
static int32 ExecutingCommand;
static int32 PendingClockDivisor;
static int32 CurrentClockDivisor;
@ -155,12 +163,12 @@ static struct
uint8 Mode[2];
bool TimeOptEn;
bool Remaining;
bool NextContBit;
uint8 CurPort;
uint8 ID1;
uint8 ID2;
uint8 IDTap;
uint8 CommMode;
@ -169,9 +177,13 @@ static struct
uint8 work[8];
//
//
uint8 TapCounter;
uint8 TapCount;
uint8 ReadCounter;
uint8 ReadCount;
uint8 ReadBuffer[255]; //16];
uint8 WriteCounter;
uint8 PDCounter;
} JRS;
//
//
@ -189,8 +201,15 @@ static struct
IODevice_Gamepad gamepad;
IODevice_3DPad threedpad;
IODevice_Mouse mouse;
IODevice_Wheel wheel;
IODevice_Mission mission{false};
IODevice_Mission dualmission{true};
IODevice_Keyboard keyboard;
} PossibleDevices[12];
static IODevice_Multitap PossibleMultitaps[2];
static IODevice_Multitap* SPorts[2];
static IODevice* VirtualPorts[12];
static uint8* VirtualPortsDPtr[12];
static uint8* MiscInputPtr;
@ -198,7 +217,8 @@ static uint8* MiscInputPtr;
IODevice::IODevice() { }
IODevice::~IODevice() { }
void IODevice::Power(void) { }
void IODevice::UpdateInput(const uint8* data) { }
void IODevice::UpdateInput(const uint8* data, const int32 time_elapsed) { }
void IODevice::UpdateOutput(uint8* data) { }
void IODevice::StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix) { }
uint8 IODevice::UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) { return smpc_out; }
@ -216,38 +236,79 @@ static void UpdateIOBus(unsigned port)
static void MapPorts(void)
{
for(unsigned port = 0; port < 2; port++)
IOPorts[port] = VirtualPorts[port];
for(unsigned sp = 0, vp = 0; sp < 2; sp++)
{
IODevice* nd;
if(SPorts[sp])
{
for(unsigned i = 0; i < 6; i++)
{
IODevice* const tsd = VirtualPorts[vp++];
if(SPorts[sp]->GetSubDevice(i) != tsd)
tsd->Power();
SPorts[sp]->SetSubDevice(i, tsd);
}
nd = SPorts[sp];
}
else
nd = VirtualPorts[vp++];
if(IOPorts[sp] != nd)
nd->Power();
IOPorts[sp] = nd;
}
}
void SMPC_SetMultitap(unsigned sport, bool enabled)
{
assert(sport < 2);
SPorts[sport] = (enabled ? &PossibleMultitaps[sport] : nullptr);
MapPorts();
}
void SMPC_SetInput(unsigned port, const char* type, uint8* ptr)
{
if(port == 12)
{
MiscInputPtr = ptr;
return;
}
assert(port < 13);
assert(port < 12);
if(port == 12)
{
MiscInputPtr = ptr;
return;
}
//
//
//
IODevice* nd = nullptr;
IODevice* nd = &PossibleDevices[port].none;
if(!strcmp(type, "none"))
nd = &PossibleDevices[port].none;
else if(!strcmp(type, "gamepad"))
nd = &PossibleDevices[port].gamepad;
else if(!strcmp(type, "3dpad"))
nd = &PossibleDevices[port].threedpad;
else if(!strcmp(type, "mouse"))
nd = &PossibleDevices[port].mouse;
else if(!strcmp(type, "wheel"))
nd = &PossibleDevices[port].wheel;
else if(!strcmp(type, "mission") || !strcmp(type, "missionwoa"))
nd = &PossibleDevices[port].mission;
else if(!strcmp(type, "dmission") || !strcmp(type, "dmissionwoa"))
nd = &PossibleDevices[port].dualmission;
else if(!strcmp(type, "keyboard"))
nd = &PossibleDevices[port].keyboard;
else
abort();
if(!strcmp(type, "gamepad"))
nd = &PossibleDevices[port].gamepad;
else if(!strcmp(type, "3dpad"))
nd = &PossibleDevices[port].threedpad;
else if(!strcmp(type, "mouse"))
nd = &PossibleDevices[port].mouse;
VirtualPorts[port] = nd;
VirtualPortsDPtr[port] = ptr;
if(nd != VirtualPorts[port])
{
VirtualPorts[port] = nd;
VirtualPorts[port]->Power();
}
VirtualPortsDPtr[port] = ptr;
MapPorts();
MapPorts();
}
#if 0
@ -421,15 +482,25 @@ int32 SMPC_StartFrame(EmulateSpecStruct* espec)
return CurrentClockDivisor;
}
void SMPC_UpdateInput(void)
void SMPC_UpdateOutput(void)
{
if (MiscInputPtr)
ResetButtonPhysStatus = (bool)(*MiscInputPtr & 0x1);
for(unsigned vp = 0; vp < 12; vp++)
{
if (VirtualPorts[vp])
VirtualPorts[vp]->UpdateInput(VirtualPortsDPtr[vp]);
}
for(unsigned vp = 0; vp < 12; vp++)
{
VirtualPorts[vp]->UpdateOutput(VirtualPortsDPtr[vp]);
}
}
void SMPC_UpdateInput(const int32 time_elapsed)
{
//printf("%8d\n", time_elapsed);
if (MiscInputPtr)
ResetButtonPhysStatus = (bool)(*MiscInputPtr & 0x1);
for(unsigned vp = 0; vp < 12; vp++)
{
if (VirtualPorts[vp])
VirtualPorts[vp]->UpdateInput(VirtualPortsDPtr[vp], time_elapsed);
}
}
@ -455,10 +526,10 @@ void SMPC_Write(const sscpu_timestamp_t timestamp, uint8 A, uint8 V)
case 0x05:
case 0x06:
#ifdef HAVE_DEBUG
if(MDFN_UNLIKELY(PendingCommand >= 0))
{
SS_DBGTI(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] Input register %u port written with 0x%02x while command 0x%02x is executing.", A, V, PendingCommand);
}
if(MDFN_UNLIKELY(ExecutingCommand >= 0))
{
SS_DBGTI(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] Input register %u port written with 0x%02x while command 0x%02x is executing.", A, V, ExecutingCommand);
}
#endif
IREG[A] = V;
@ -466,10 +537,10 @@ void SMPC_Write(const sscpu_timestamp_t timestamp, uint8 A, uint8 V)
case 0x0F:
#ifdef HAVE_DEBUG
if(MDFN_UNLIKELY(PendingCommand >= 0))
{
SS_DBGTI(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] Command port written with 0x%02x while command 0x%02x is still executing.", V, PendingCommand);
}
if(MDFN_UNLIKELY(ExecutingCommand >= 0))
{
SS_DBGTI(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] Command port written with 0x%02x while command 0x%02x is still executing.", V, ExecutingCommand);
}
#endif
PendingCommand = V;
@ -551,10 +622,10 @@ uint8 SMPC_Read(const sscpu_timestamp_t timestamp, uint8 A)
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F:
#ifdef HAVE_DEBUG
if(MDFN_UNLIKELY(PendingCommand >= 0))
{
//SS_DBG(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] Output register %u port read while command 0x%02x is executing.\n", A - 0x10, PendingCommand);
}
if(MDFN_UNLIKELY(ExecutingCommand >= 0))
{
//SS_DBG(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] Output register %u port read while command 0x%02x is executing.\n", A - 0x10, ExecutingCommand);
}
#endif
ret = (OREG - 0x10)[A];
@ -562,10 +633,10 @@ uint8 SMPC_Read(const sscpu_timestamp_t timestamp, uint8 A)
case 0x30:
#ifdef HAVE_DEBUG
if(MDFN_UNLIKELY(PendingCommand >= 0))
{
//SS_DBG(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] SR port read while command 0x%02x is executing.\n", PendingCommand);
}
if(MDFN_UNLIKELY(ExecutingCommand >= 0))
{
//SS_DBG(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] SR port read while command 0x%02x is executing.\n", ExecutingCommand);
}
#endif
ret = SR;
@ -717,7 +788,7 @@ sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp)
if(MDFN_UNLIKELY(timestamp < lastts))
{
SS_DBG(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] [BUG] timestamp(%d) < lastts(%d)\n", timestamp, lastts);
//SS_DBG(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] [BUG] timestamp(%d) < lastts(%d)\n", timestamp, lastts);
clocks = 0;
}
else
@ -787,56 +858,56 @@ sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp)
continue;
}
ExecutingCommand = PendingCommand;
PendingCommand = -1;
SMPC_EAT_CLOCKS(92);
if(PendingCommand < 0x20)
if(ExecutingCommand < 0x20)
{
OREG[0x1F] = PendingCommand;
OREG[0x1F] = ExecutingCommand;
#ifdef HAVE_DEBUG
SS_DBGTI(SS_DBG_SMPC, "[SMPC] Command 0x%02x --- 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", PendingCommand, IREG[0], IREG[1], IREG[2], IREG[3], IREG[4], IREG[5], IREG[6]);
#endif
SS_DBGTI(SS_DBG_SMPC, "[SMPC] Command 0x%02x --- 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", ExecutingCommand, IREG[0], IREG[1], IREG[2], IREG[3], IREG[4], IREG[5], IREG[6]);
if(PendingCommand == CMD_MSHON)
if(ExecutingCommand == CMD_MSHON)
{
}
else if(PendingCommand == CMD_SSHON)
else if(ExecutingCommand == CMD_SSHON)
{
if(!SlaveSH2On)
SlaveOn();
}
else if(PendingCommand == CMD_SSHOFF)
else if(ExecutingCommand == CMD_SSHOFF)
{
if(SlaveSH2On)
SlaveOff();
}
else if(PendingCommand == CMD_SNDON)
else if(ExecutingCommand == CMD_SNDON)
{
if(!SoundCPUOn)
TurnSoundCPUOn();
}
else if(PendingCommand == CMD_SNDOFF)
else if(ExecutingCommand == CMD_SNDOFF)
{
if(SoundCPUOn)
TurnSoundCPUOff();
}
else if(PendingCommand == CMD_CDON)
else if(ExecutingCommand == CMD_CDON)
{
CDOn = true;
}
else if(PendingCommand == CMD_CDOFF)
else if(ExecutingCommand == CMD_CDOFF)
{
CDOn = false;
}
else if(PendingCommand == CMD_SYSRES)
else if(ExecutingCommand == CMD_SYSRES)
{
ResetPending = true;
SMPC_WAIT_UNTIL_COND(!ResetPending);
// TODO/FIXME(unreachable currently?):
}
else if(PendingCommand == CMD_CKCHG352 || PendingCommand == CMD_CKCHG320)
else if(ExecutingCommand == CMD_CKCHG352 || ExecutingCommand == CMD_CKCHG320)
{
// Devour some time
@ -852,7 +923,7 @@ sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp)
SCU_Reset(false);
// Change clock
PendingClockDivisor = (PendingCommand == CMD_CKCHG352) ? CLOCK_DIVISOR_28M : CLOCK_DIVISOR_26M;
PendingClockDivisor = (ExecutingCommand == CMD_CKCHG352) ? CLOCK_DIVISOR_28M : CLOCK_DIVISOR_26M;
// Wait for a few vblanks
SMPC_WAIT_UNTIL_COND(!vb);
@ -870,7 +941,7 @@ sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp)
CPU[0].SetNMI(false);
CPU[0].SetNMI(true);
}
else if(PendingCommand == CMD_INTBACK)
else if(ExecutingCommand == CMD_INTBACK)
{
//SS_DBGTI(SS_DBG_SMPC, "[SMPC] INTBACK IREG0=0x%02x, IREG1=0x%02x, IREG2=0x%02x, %d", IREG[0], IREG[1], IREG[2], vb);
@ -914,9 +985,30 @@ sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp)
{
#define JR_WAIT(cond) { SMPC_WAIT_UNTIL_COND((cond) || PendingVB); if(PendingVB) { SS_DBGTI(SS_DBG_SMPC, "[SMPC] abortjr wait"); goto AbortJR; } }
#define JR_EAT(n) { SMPC_EAT_CLOCKS(n); if(PendingVB) { SS_DBGTI(SS_DBG_SMPC, "[SMPC] abortjr eat"); goto AbortJR; } }
#define JR_WRNYB(val) \
{ \
/*if(!JRS.OWP) { JR_WAIT((bool)(IREG[0] & 0x80) == JRS.NextContBit); JRS.NextContBit = !JRS.NextContBit; }*/ \
#define JR_WRNYB(val) \
{ \
if(!JRS.OWP) \
{ \
if(JRS.PDCounter > 0) \
{ \
SR = (SR & ~SR_PDL) | ((JRS.PDCounter < 0x2) ? SR_PDL : 0); \
SR = (SR & ~0xF) | (JRS.Mode[0] << 0) | (JRS.Mode[1] << 2); \
SR |= SR_NPE; \
SR |= 0x80; \
SCU_SetInt(SCU_INT_SMPC, true); \
SCU_SetInt(SCU_INT_SMPC, false); \
JR_WAIT((bool)(IREG[0] & 0x80) == JRS.NextContBit || (IREG[0] & 0x40)); \
if(IREG[0] & 0x40) \
{ \
SS_DBGTI(SS_DBG_SMPC, "[SMPC] Big Read Break"); \
goto AbortJR; \
} \
JRS.NextContBit = !JRS.NextContBit; \
} \
if(JRS.PDCounter < 0xFF) \
JRS.PDCounter++; \
} \
\
OREG[(JRS.OWP >> 1)] &= 0x0F << ((JRS.OWP & 1) << 2); \
OREG[(JRS.OWP >> 1)] |= ((val) & 0xF) << (((JRS.OWP & 1) ^ 1) << 2); \
JRS.OWP = (JRS.OWP + 1) & 0x3F; \
@ -944,6 +1036,7 @@ sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp)
JRS.NextContBit = !JRS.NextContBit;
}
JRS.PDCounter = 0;
JRS.TimeOptEn = !(IREG[1] & 0x2);
JRS.Mode[0] = (IREG[1] >> 4) & 0x3;
JRS.Mode[1] = (IREG[1] >> 6) & 0x3;
@ -970,7 +1063,10 @@ sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp)
{
JR_EAT(380);
// TODO: Check read size mode.
if(JRS.Mode[JRS.CurPort] & 0x2)
continue;
// TODO: 255-byte read size mode.
JRS.ID1 = 0;
JR_TH_TR(1, 1);
@ -1040,49 +1136,87 @@ sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp)
JR_WAIT(JR_BS & 0x10);
JRS.ID2 |= ((JR_BS & 0xF) << 0);
//printf("%d, %02x %02x\n", JRS.CurPort, JRS.ID1, JRS.ID2);
if(JRS.ID1 == 0x3)
JRS.ID2 = 0xE3;
JRS.ReadCounter = 0;
while(JRS.ReadCounter < (JRS.ID2 & 0xF))
{
if((JRS.ID2 & 0xF0) == 0x40) // Multitap
{
JR_TH_TR(0, 0)
JR_EAT(50);
JR_WAIT(!(JR_BS & 0x10));
JRS.ReadBuffer[JRS.ReadCounter] = ((JR_BS & 0xF) << 4);
JRS.IDTap = ((JRS.ID2 & 0xF) << 4) | (JR_BS & 0xF);
JR_TH_TR(0, 1)
JR_EAT(50);
JR_WAIT(JR_BS & 0x10);
JRS.ReadBuffer[JRS.ReadCounter] |= ((JR_BS & 0xF) << 0);
JRS.ReadCounter++;
}
else
JRS.IDTap = 0xF1;
JRS.TapCounter = 0;
JRS.TapCount = (JRS.IDTap & 0xF);
while(JRS.TapCounter < JRS.TapCount)
{
if(JRS.TapCount > 1)
{
JR_TH_TR(0, 0)
JR_EAT(50);
JR_WAIT(!(JR_BS & 0x10));
JRS.ID2 = ((JR_BS & 0xF) << 4);
JR_TH_TR(0, 1)
JR_EAT(50);
JR_WAIT(JR_BS & 0x10);
JRS.ID2 |= ((JR_BS & 0xF) << 0);
}
JRS.ReadCounter = 0;
JRS.ReadCount = ((JRS.ID2 & 0xF0) == 0xF0) ? 0 : (JRS.ID2 & 0xF);
while(JRS.ReadCounter < JRS.ReadCount)
{
JR_TH_TR(0, 0)
JR_EAT(50);
JR_WAIT(!(JR_BS & 0x10));
JRS.ReadBuffer[JRS.ReadCounter] = ((JR_BS & 0xF) << 4);
JR_TH_TR(0, 1)
JR_EAT(50);
JR_WAIT(JR_BS & 0x10);
JRS.ReadBuffer[JRS.ReadCounter] |= ((JR_BS & 0xF) << 0);
JRS.ReadCounter++;
}
if(!JRS.TapCounter)
{
JR_WRNYB(JRS.IDTap >> 4);
JR_EAT(21);
JR_WRNYB(JRS.IDTap >> 0);
JR_EAT(21);
}
//printf("What: %d, %02x\n", JRS.TapCounter, JRS.ID2);
JR_WRNYB(JRS.ID2 >> 4);
JR_EAT(21);
JR_WRNYB(JRS.ID2 >> 0);
JR_EAT(21);
JRS.WriteCounter = 0;
while(JRS.WriteCounter < JRS.ReadCounter)
{
JR_WRNYB(JRS.ReadBuffer[JRS.WriteCounter] >> 4);
JR_EAT(21);
JR_WRNYB(JRS.ReadBuffer[JRS.WriteCounter] >> 0);
JR_EAT(21);
JRS.WriteCounter++;
}
JRS.TapCounter++;
}
JR_WRNYB(0xF);
JR_EAT(21);
JR_WRNYB(0x1);
JR_EAT(21);
JR_WRNYB(JRS.ID2 >> 4);
JR_EAT(21);
JR_WRNYB(JRS.ID2 >> 0);
JR_EAT(21);
JRS.WriteCounter = 0;
while(JRS.WriteCounter < JRS.ReadCounter)
{
JR_WRNYB(JRS.ReadBuffer[JRS.WriteCounter] >> 4);
JR_EAT(21);
JR_WRNYB(JRS.ReadBuffer[JRS.WriteCounter] >> 0);
JR_EAT(21);
JRS.WriteCounter++;
}
// Saturn analog joystick, keyboard, multitap
// OREG[0x0] = 0xF1; // Upper nybble, multitap ID. Lower nybble, number of connected devices behind multitap.
// OREG[0x1] = 0x02; // Upper nybble, peripheral ID 2. Lower nybble, data size.
@ -1091,19 +1225,14 @@ sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp)
{
JR_WRNYB(0xF);
JR_WRNYB(0x0);
JR_WRNYB(0x0);
JR_WRNYB(0x0);
}
JR_EAT(26);
JR_TH_TR(-1, -1);
}
SR &= ~SR_NPE;
SR &= ~0xF;
SR |= JRS.Mode[0] << 0;
SR |= JRS.Mode[1] << 2;
SR |= SR_PDL;
SR = (SR & ~SR_NPE);
SR = (SR & ~0xF) | (JRS.Mode[0] << 0) | (JRS.Mode[1] << 2);
SR = (SR & ~SR_PDL) | ((JRS.PDCounter < 0x2) ? SR_PDL : 0);
SR |= 0x80;
SCU_SetInt(SCU_INT_SMPC, true);
SCU_SetInt(SCU_INT_SMPC, false);
@ -1114,7 +1243,7 @@ sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp)
AbortJR:;
// TODO: Set TH TR to inputs on abort.
}
else if(PendingCommand == CMD_SETTIME) // Warning: Execute RTC setting atomically(all values or none) in regards to emulator exit/power toggle.
else if(ExecutingCommand == CMD_SETTIME) // Warning: Execute RTC setting atomically(all values or none) in regards to emulator exit/power toggle.
{
SMPC_EAT_CLOCKS(380);
@ -1124,29 +1253,29 @@ sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp)
for(unsigned i = 0; i < 7; i++)
RTC.raw[i] = IREG[i];
}
else if(PendingCommand == CMD_SETSMEM) // Warning: Execute save mem setting(all values or none) atomically in regards to emulator exit/power toggle.
else if(ExecutingCommand == CMD_SETSMEM) // Warning: Execute save mem setting(all values or none) atomically in regards to emulator exit/power toggle.
{
SMPC_EAT_CLOCKS(234);
for(unsigned i = 0; i < 4; i++)
SaveMem[i] = IREG[i];
}
else if(PendingCommand == CMD_NMIREQ)
else if(ExecutingCommand == CMD_NMIREQ)
{
CPU[0].SetNMI(false);
CPU[0].SetNMI(true);
}
else if(PendingCommand == CMD_RESENAB)
else if(ExecutingCommand == CMD_RESENAB)
{
ResetNMIEnable = true;
}
else if(PendingCommand == CMD_RESDISA)
else if(ExecutingCommand == CMD_RESDISA)
{
ResetNMIEnable = false;
}
}
PendingCommand = -1;
ExecutingCommand = -1;
SF = false;
continue;
}
@ -1166,7 +1295,7 @@ void SMPC_SetVB(sscpu_timestamp_t event_timestamp, bool vb_status)
vb = vb_status;
}
static const std::vector<InputDeviceInfoStruct> InputDeviceInfoSSPort =
static const std::vector<InputDeviceInfoStruct> InputDeviceInfoSSVPort =
{
// None
{
@ -1199,6 +1328,57 @@ static const std::vector<InputDeviceInfoStruct> InputDeviceInfoSSPort =
"Mouse",
IODevice_Mouse_IDII,
},
// Steering Wheel
{
"wheel",
"Steering Wheel",
"Arcade Racer/Racing Controller",
IODevice_Wheel_IDII
},
// Mission Stick
{
"mission",
"Mission Stick",
"Mission Stick",
IODevice_Mission_IDII
},
#if 0
// Mission Stick (No Autofire)
{
"missionwoa",
"Mission (No AF)",
"Mission Stick, without autofire functionality(for less things to map).",
IODevice_MissionNoAF_IDII
},
#endif
// Dual Mission Stick
{
"dmission",
"Dual Mission",
"Dual Mission Sticks, useful for \"Panzer Dragoon Zwei\". With 30 inputs to map, don't get distracted by..LOOK A LOBSTER!",
IODevice_DualMission_IDII
},
#if 0
// Dual Mission Stick (No Autofire)
{
"dmissionwoa",
"Dual Mission (No AF)",
"Dual Mission Sticks (No Autofire)",
IODevice_DualMissionNoAF_IDII
},
#endif
// Keyboard (101-key US)
{
"keyboard",
"Keyboard (US)",
"101-key US keyboard.",
IODevice_Keyboard_US101_IDII,
InputDeviceInfoStruct::FLAG_KEYBOARD
},
};
static IDIISG IDII_Builtin =
@ -1219,18 +1399,18 @@ static const std::vector<InputDeviceInfoStruct> InputDeviceInfoBuiltin =
const std::vector<InputPortInfoStruct> SMPC_PortInfo =
{
{ "port1", "Virtual Port 1", InputDeviceInfoSSPort, "gamepad" },
{ "port2", "Virtual Port 2", InputDeviceInfoSSPort, "gamepad" },
{ "port3", "Virtual Port 3", InputDeviceInfoSSPort, "gamepad" },
{ "port4", "Virtual Port 4", InputDeviceInfoSSPort, "gamepad" },
{ "port5", "Virtual Port 5", InputDeviceInfoSSPort, "gamepad" },
{ "port6", "Virtual Port 6", InputDeviceInfoSSPort, "gamepad" },
{ "port7", "Virtual Port 7", InputDeviceInfoSSPort, "gamepad" },
{ "port8", "Virtual Port 8", InputDeviceInfoSSPort, "gamepad" },
{ "port9", "Virtual Port 9", InputDeviceInfoSSPort, "gamepad" },
{ "port10", "Virtual Port 10", InputDeviceInfoSSPort, "gamepad" },
{ "port11", "Virtual Port 11", InputDeviceInfoSSPort, "gamepad" },
{ "port12", "Virtual Port 12", InputDeviceInfoSSPort, "gamepad" },
{ "port1", "Virtual Port 1", InputDeviceInfoSSVPort, "gamepad" },
{ "port2", "Virtual Port 2", InputDeviceInfoSSVPort, "gamepad" },
{ "port3", "Virtual Port 3", InputDeviceInfoSSVPort, "gamepad" },
{ "port4", "Virtual Port 4", InputDeviceInfoSSVPort, "gamepad" },
{ "port5", "Virtual Port 5", InputDeviceInfoSSVPort, "gamepad" },
{ "port6", "Virtual Port 6", InputDeviceInfoSSVPort, "gamepad" },
{ "port7", "Virtual Port 7", InputDeviceInfoSSVPort, "gamepad" },
{ "port8", "Virtual Port 8", InputDeviceInfoSSVPort, "gamepad" },
{ "port9", "Virtual Port 9", InputDeviceInfoSSVPort, "gamepad" },
{ "port10", "Virtual Port 10", InputDeviceInfoSSVPort, "gamepad" },
{ "port11", "Virtual Port 11", InputDeviceInfoSSVPort, "gamepad" },
{ "port12", "Virtual Port 12", InputDeviceInfoSSVPort, "gamepad" },
{ "builtin", "Builtin", InputDeviceInfoBuiltin, "builtin" },
};

View File

@ -2,7 +2,7 @@
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* smpc.h:
** Copyright (C) 2015-2016 Mednafen Team
** Copyright (C) 2015-2017 Mednafen Team
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
@ -68,8 +68,10 @@ sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp);
void SMPC_ResetTS(void);
int32 SMPC_StartFrame(EmulateSpecStruct* espec);
void SMPC_UpdateInput(void);
void SMPC_UpdateInput(const int32 time_elapsed);
void SMPC_UpdateOutput(void);
void SMPC_SetInput(unsigned port, const char* type, uint8* ptr);
void SMPC_SetMultitap(unsigned sport, bool enabled);
void SMPC_SetVB(sscpu_timestamp_t event_timestamp, bool vb_status);
@ -81,7 +83,13 @@ class IODevice
virtual ~IODevice();
virtual void Power(void);
virtual void UpdateInput(const uint8* data);
//
// time_elapsed is emulated time elapsed since last call to UpdateInput(), in microseconds;
// it's mostly for keyboard emulation, to keep the implementation from becoming unnecessarily complex.
//
virtual void UpdateInput(const uint8* data, const int32 time_elapsed);
virtual void UpdateOutput(uint8* data);
virtual void StateAction(StateMem* sm, const unsigned load, const bool data_only, const char* sname_prefix);
virtual uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted);
};