diff --git a/waterbox/o2em/main.c b/waterbox/o2em/main.c index 24ebc07497..ea8380987d 100644 --- a/waterbox/o2em/main.c +++ b/waterbox/o2em/main.c @@ -76,7 +76,7 @@ ECL_EXPORT int Init(const char *rom, int romlen, const char *bios, int bioslen) ECL_EXPORT void FrameAdvance(FrameInfo* f) { - cpu_exec(20000); + cpu_exec(6026); f->Samples = 735; f->Width = 320; f->Height = 240; diff --git a/waterbox/o2em/vmachine.c b/waterbox/o2em/vmachine.c index 1460e8550d..e1fe648466 100644 --- a/waterbox/o2em/vmachine.c +++ b/waterbox/o2em/vmachine.c @@ -221,7 +221,7 @@ Byte read_P2(void) { int i, si, so, km; - return 0; + return 0xff; // TODO /*if (NeedsPoll) poll_keyboard(); diff --git a/waterbox/ss/bizhawk.cpp b/waterbox/ss/bizhawk.cpp index 98e798e69d..a58898c1f9 100644 --- a/waterbox/ss/bizhawk.cpp +++ b/waterbox/ss/bizhawk.cpp @@ -1,5 +1,4 @@ #include "ss.h" -#include "stream/MemoryStream.h" #include #include "cdrom/cdromif.h" #include "cdb.h" @@ -257,26 +256,7 @@ EXPORT void SetVideoParameters(bool correctAspect, bool hBlend, bool hOverscan, Cleanup(); }*/ -/*static MDFN_COLD void SaveBackupRAM(void) -{ - FileStream brs(MDFN_MakeFName(MDFNMKF_SAV, 0, "bkr"), FileStream::MODE_WRITE_INPLACE); - - brs.write(BackupRAM, sizeof(BackupRAM)); - - brs.close(); -} - -static MDFN_COLD void LoadBackupRAM(void) -{ - FileStream brs(MDFN_MakeFName(MDFNMKF_SAV, 0, "bkr"), FileStream::MODE_READ); - - brs.read(BackupRAM, sizeof(BackupRAM)); -} - -static MDFN_COLD void BackupBackupRAM(void) -{ - MDFN_BackupSavFile(10, "bkr"); -} +/* static MDFN_COLD void BackupCartNV(void) { diff --git a/waterbox/ss/cdrom/cdromif.h b/waterbox/ss/cdrom/cdromif.h index aafaf8b449..51125e8409 100644 --- a/waterbox/ss/cdrom/cdromif.h +++ b/waterbox/ss/cdrom/cdromif.h @@ -1,64 +1,59 @@ -/* 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 - */ - -#ifndef __MDFN_CDROM_CDROMIF_H -#define __MDFN_CDROM_CDROMIF_H - -#include "CDUtility.h" -#include "stream/Stream.h" - -#include - -typedef CDUtility::TOC CD_TOC; - -class CDIF -{ - public: - - CDIF(); - virtual ~CDIF(); - - static const int32 LBA_Read_Minimum = -150; - static const int32 LBA_Read_Maximum = 449849; // 100 * 75 * 60 - 150 - 1 - - inline void ReadTOC(CDUtility::TOC *read_target) - { - *read_target = disc_toc; - } - - virtual void HintReadSector(int32 lba) = 0; - virtual bool ReadRawSector(uint8 *buf, int32 lba) = 0; // Reads 2352+96 bytes of data into buf. - virtual bool ReadRawSectorPWOnly(uint8* pwbuf, int32 lba, bool hint_fullread) = 0; // Reads 96 bytes(of raw subchannel PW data) into pwbuf. - - // Call for mode 1 or mode 2 form 1 only. - bool ValidateRawSector(uint8 *buf); - - // Utility/Wrapped functions - // Reads mode 1 and mode2 form 1 sectors(2048 bytes per sector returned) - // Will return the type(1, 2) of the first sector read to the buffer supplied, 0 on error - int ReadSector(uint8* buf, int32 lba, uint32 sector_count, bool suppress_uncorrectable_message = false); - - // For Mode 1, or Mode 2 Form 1. - // No reference counting or whatever is done, so if you destroy the CDIF object before you destroy the returned Stream, things will go BOOM. - Stream *MakeStream(int32 lba, uint32 sector_count); - - protected: - bool UnrecoverableError; - CDUtility::TOC disc_toc; -}; - -#endif +/* 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 + */ + +#ifndef __MDFN_CDROM_CDROMIF_H +#define __MDFN_CDROM_CDROMIF_H + +#include "CDUtility.h" + +#include + +typedef CDUtility::TOC CD_TOC; + +class CDIF +{ + public: + + CDIF(); + virtual ~CDIF(); + + static const int32 LBA_Read_Minimum = -150; + static const int32 LBA_Read_Maximum = 449849; // 100 * 75 * 60 - 150 - 1 + + inline void ReadTOC(CDUtility::TOC *read_target) + { + *read_target = disc_toc; + } + + virtual void HintReadSector(int32 lba) = 0; + virtual bool ReadRawSector(uint8 *buf, int32 lba) = 0; // Reads 2352+96 bytes of data into buf. + virtual bool ReadRawSectorPWOnly(uint8* pwbuf, int32 lba, bool hint_fullread) = 0; // Reads 96 bytes(of raw subchannel PW data) into pwbuf. + + // Call for mode 1 or mode 2 form 1 only. + bool ValidateRawSector(uint8 *buf); + + // Utility/Wrapped functions + // Reads mode 1 and mode2 form 1 sectors(2048 bytes per sector returned) + // Will return the type(1, 2) of the first sector read to the buffer supplied, 0 on error + int ReadSector(uint8* buf, int32 lba, uint32 sector_count, bool suppress_uncorrectable_message = false); + + protected: + bool UnrecoverableError; + CDUtility::TOC disc_toc; +}; + +#endif diff --git a/waterbox/ss/defs.h b/waterbox/ss/defs.h index 6bd9c75ce4..127cf2ef86 100644 --- a/waterbox/ss/defs.h +++ b/waterbox/ss/defs.h @@ -85,219 +85,8 @@ typedef struct #define MDFN_FORMATSTR(...) #define require assert -enum InputDeviceInputType : uint8 -{ - IDIT_BUTTON, // 1-bit - IDIT_BUTTON_CAN_RAPID, // 1-bit - - IDIT_SWITCH, // ceil(log2(n))-bit - // Current switch position(default 0). - // Persistent, and bidirectional communication(can be modified driver side, and Mednafen core and emulation module side) - - IDIT_STATUS, // ceil(log2(n))-bit - // emulation module->driver communication - - IDIT_X_AXIS, // (mouse) 16-bits, signed - in-screen/window range: [0.0, nominal_width) - IDIT_Y_AXIS, // (mouse) 16-bits, signed - in-screen/window range: [0.0, nominal_height) - - IDIT_X_AXIS_REL, // (mouse) 32-bits, signed - IDIT_Y_AXIS_REL, // (mouse) 32-bits, signed - - IDIT_BYTE_SPECIAL, - - IDIT_RESET_BUTTON, // 1-bit - - IDIT_BUTTON_ANALOG, // 16-bits, 0 - 32767 - - IDIT_RUMBLE, // 16-bits, lower 8 bits are weak rumble(0-255), next 8 bits are strong rumble(0-255), 0=no rumble, 255=max rumble. Somewhat subjective, too... - // It's a rather special case of game module->driver code communication. -}; - -#define IDIT_BUTTON_ANALOG_FLAG_SQLR 0x00000001 // Denotes analog data that may need to be scaled to ensure a more squareish logical range(for emulated - // analog sticks). -struct IDIIS_StatusState -{ - const char *ShortName; - const char *Name; - int32 Color; // (msb)0RGB(lsb), -1 for unused. -}; -struct InputDeviceInputInfoStruct -{ - const char *SettingName; // No spaces, shouldbe all a-z0-9 and _. Definitely no ~! - const char *Name; - int ConfigOrder; // Configuration order during in-game config process, -1 for no config. - InputDeviceInputType Type; - const char *ExcludeName; // SettingName of a button that can't be pressed at the same time as this button - // due to physical limitations. - uint8 Flags; - uint8 BitSize; - uint16 BitOffset; - - union { - struct - { - const char *const *SwitchPosName; // - uint32 SwitchNumPos; - }; - - struct - { - const IDIIS_StatusState *StatusStates; - uint32 StatusNumStates; - }; - }; -}; - -struct IDIISG : public std::vector -{ - IDIISG() - { - InputByteSize = 0; - } - - IDIISG(std::initializer_list l) : std::vector(l) - { - size_t bit_offset = 0; - - for (auto &idii : *this) - { - size_t bit_size = 0; - size_t bit_align = 1; - - switch (idii.Type) - { - default: - abort(); - break; - - case IDIT_BUTTON: - case IDIT_BUTTON_CAN_RAPID: - case IDIT_RESET_BUTTON: - bit_size = 1; - break; - - case IDIT_SWITCH: - bit_size = ceil(log2(idii.SwitchNumPos)); - break; - - case IDIT_STATUS: - bit_size = ceil(log2(idii.StatusNumStates)); - break; - - case IDIT_X_AXIS: - case IDIT_Y_AXIS: - bit_size = 16; - bit_align = 8; - break; - - case IDIT_X_AXIS_REL: - case IDIT_Y_AXIS_REL: - bit_size = 32; - bit_align = 8; - break; - - case IDIT_BYTE_SPECIAL: - bit_size = 8; - bit_align = 8; - break; - - case IDIT_BUTTON_ANALOG: - bit_size = 16; - bit_align = 8; - break; - - case IDIT_RUMBLE: - bit_size = 16; - bit_align = 8; - break; - } - - bit_offset = (bit_offset + (bit_align - 1)) & ~(bit_align - 1); - - // printf("%s, %zu(%zu)\n", idii.SettingName, bit_offset, bit_offset / 8); - - idii.BitSize = bit_size; - idii.BitOffset = bit_offset; - - assert(idii.BitSize == bit_size); - assert(idii.BitOffset == bit_offset); - - bit_offset += bit_size; - } - - InputByteSize = (bit_offset + 7) / 8; - } - uint32 InputByteSize; -}; - -struct IDIIS_Switch : public InputDeviceInputInfoStruct -{ - IDIIS_Switch(const char *sname, const char *name, int co, const char *const *spn, const uint32 spn_num) - { - SettingName = sname; - Name = name; - ConfigOrder = co; - Type = IDIT_SWITCH; - - ExcludeName = NULL; - Flags = 0; - SwitchPosName = spn; - SwitchNumPos = spn_num; - } -}; - -struct IDIIS_Status : public InputDeviceInputInfoStruct -{ - IDIIS_Status(const char *sname, const char *name, const IDIIS_StatusState *ss, const uint32 ss_num) - { - SettingName = sname; - Name = name; - ConfigOrder = -1; - Type = IDIT_STATUS; - - ExcludeName = NULL; - Flags = 0; - StatusStates = ss; - StatusNumStates = ss_num; - } -}; - -struct InputDeviceInfoStruct -{ - const char *ShortName; - const char *FullName; - const char *Description; - - const IDIISG &IDII; - - unsigned Flags; - - enum - { - FLAG_KEYBOARD = (1U << 0) - }; -}; - -struct InputPortInfoStruct -{ - const char *ShortName; - const char *FullName; - const std::vector &DeviceInfo; - const char *DefaultDevice; // Default device for this port. -}; - #include "endian.h" -inline char *strdup(const char *p) -{ - char *ret = (char *)malloc(strlen(p) + 1); - if (ret) - strcpy(ret, p); - return ret; -} - -#include "stream/Stream.h" -#include "stream/MemoryStream.h" #include "math_ops.h" #include "../emulibc/emulibc.h" diff --git a/waterbox/ss/input/3dpad.cpp b/waterbox/ss/input/3dpad.cpp index 7246440709..04c489ec88 100644 --- a/waterbox/ss/input/3dpad.cpp +++ b/waterbox/ss/input/3dpad.cpp @@ -128,41 +128,4 @@ uint8 IODevice_3DPad::UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asser return (smpc_out & (smpc_out_asserted | 0xE0)) | (tmp &~ smpc_out_asserted); } -static const char* const ModeSwitchPositions[] = -{ - gettext_noop("Digital(+)"), - gettext_noop("Analog(○)"), -}; - -IDIISG IODevice_3DPad_IDII = -{ - { "up", "D-Pad UP ↑", 0, IDIT_BUTTON, "down" }, - { "down", "D-Pad DOWN ↓", 1, IDIT_BUTTON, "up" }, - { "left", "D-Pad LEFT ←", 2, IDIT_BUTTON, "right" }, - { "right", "D-Pad RIGHT →", 3, IDIT_BUTTON, "left" }, - - { "b", "B", 6, IDIT_BUTTON }, - { "c", "C", 7, IDIT_BUTTON }, - { "a", "A", 5, IDIT_BUTTON }, - { "start", "START", 4, IDIT_BUTTON }, - - { "z", "Z", 10, IDIT_BUTTON }, - { "y", "Y", 9, IDIT_BUTTON }, - { "x", "X", 8, IDIT_BUTTON }, - { NULL, "empty", 0, IDIT_BUTTON }, - - IDIIS_Switch("mode", "Mode", 17, ModeSwitchPositions, sizeof(ModeSwitchPositions) / sizeof(ModeSwitchPositions[0])), - - { "analog_left", "Analog LEFT ←", 15, IDIT_BUTTON_ANALOG }, - { "analog_right", "Analog RIGHT →", 16, IDIT_BUTTON_ANALOG }, - { "analog_up", "Analog UP ↑", 13, IDIT_BUTTON_ANALOG }, - { "analog_down", "Analog DOWN ↓", 14, IDIT_BUTTON_ANALOG }, - - { "rs", "Right Shoulder (Analog)", 12, IDIT_BUTTON_ANALOG }, - { "ls", "Left Shoulder (Analog)", 11, IDIT_BUTTON_ANALOG }, -}; - - - - } diff --git a/waterbox/ss/input/3dpad.h b/waterbox/ss/input/3dpad.h index 413506cc85..0eea5a60d3 100644 --- a/waterbox/ss/input/3dpad.h +++ b/waterbox/ss/input/3dpad.h @@ -1,56 +1,53 @@ -/******************************************************************************/ -/* Mednafen Sega Saturn Emulation Module */ -/******************************************************************************/ -/* 3dpad.h: -** 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 -** 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_3DPAD_H -#define __MDFN_SS_INPUT_3DPAD_H - -namespace MDFN_IEN_SS -{ - -class IODevice_3DPad final : public IODevice -{ - public: - IODevice_3DPad() MDFN_COLD; - virtual ~IODevice_3DPad() override MDFN_COLD; - - virtual void Power(void) override MDFN_COLD; - virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; - - virtual uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) override; - - private: - uint16 dbuttons; - uint8 thumb[2]; - uint8 shoulder[2]; - - uint8 buffer[0x10]; - uint8 data_out; - bool tl; - int8 phase; - bool mode; -}; - - -extern IDIISG IODevice_3DPad_IDII; - -} - -#endif +/******************************************************************************/ +/* Mednafen Sega Saturn Emulation Module */ +/******************************************************************************/ +/* 3dpad.h: +** 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 +** 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_3DPAD_H +#define __MDFN_SS_INPUT_3DPAD_H + +namespace MDFN_IEN_SS +{ + +class IODevice_3DPad final : public IODevice +{ + public: + IODevice_3DPad() MDFN_COLD; + virtual ~IODevice_3DPad() override MDFN_COLD; + + virtual void Power(void) override MDFN_COLD; + virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; + + virtual uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) override; + + private: + uint16 dbuttons; + uint8 thumb[2]; + uint8 shoulder[2]; + + uint8 buffer[0x10]; + uint8 data_out; + bool tl; + int8 phase; + bool mode; +}; + +} + +#endif diff --git a/waterbox/ss/input/gamepad.cpp b/waterbox/ss/input/gamepad.cpp index 0829448cac..80e3560242 100644 --- a/waterbox/ss/input/gamepad.cpp +++ b/waterbox/ss/input/gamepad.cpp @@ -1,81 +1,57 @@ -/******************************************************************************/ -/* Mednafen Sega Saturn Emulation Module */ -/******************************************************************************/ -/* gamepad.cpp - Digital Gamepad Emulation -** 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 -** 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 "gamepad.h" - -namespace MDFN_IEN_SS -{ - -IODevice_Gamepad::IODevice_Gamepad() : buttons(~3) -{ - -} - -IODevice_Gamepad::~IODevice_Gamepad() -{ - -} - -void IODevice_Gamepad::Power(void) -{ - -} - -void IODevice_Gamepad::UpdateInput(const uint8* data, const int32 time_elapsed) -{ - buttons = (~(data[0] | (data[1] << 8))) &~ 0x3000; -} - -uint8 IODevice_Gamepad::UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) -{ - uint8 tmp; - - tmp = (buttons >> ((smpc_out >> 5) << 2)) & 0xF; - - return 0x10 | (smpc_out & (smpc_out_asserted | 0xE0)) | (tmp &~ smpc_out_asserted); -} - -IDIISG IODevice_Gamepad_IDII = -{ - { "z", "Z", 10, IDIT_BUTTON }, - { "y", "Y", 9, IDIT_BUTTON }, - { "x", "X", 8, IDIT_BUTTON }, - { "rs", "Right Shoulder", 12, IDIT_BUTTON }, - - { "up", "UP ↑", 0, IDIT_BUTTON, "down" }, - { "down", "DOWN ↓", 1, IDIT_BUTTON, "up" }, - { "left", "LEFT ←", 2, IDIT_BUTTON, "right" }, - { "right", "RIGHT →", 3, IDIT_BUTTON, "left" }, - - { "b", "B", 6, IDIT_BUTTON }, - { "c", "C", 7, IDIT_BUTTON }, - { "a", "A", 5, IDIT_BUTTON }, - { "start", "START", 4, IDIT_BUTTON }, - - { NULL, "empty", 0, IDIT_BUTTON }, - { NULL, "empty", 0, IDIT_BUTTON }, - { NULL, "empty", 0, IDIT_BUTTON }, - { "ls", "Left Shoulder", 11, IDIT_BUTTON }, -}; - - -} +/******************************************************************************/ +/* Mednafen Sega Saturn Emulation Module */ +/******************************************************************************/ +/* gamepad.cpp - Digital Gamepad Emulation +** 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 +** 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 "gamepad.h" + +namespace MDFN_IEN_SS +{ + +IODevice_Gamepad::IODevice_Gamepad() : buttons(~3) +{ + +} + +IODevice_Gamepad::~IODevice_Gamepad() +{ + +} + +void IODevice_Gamepad::Power(void) +{ + +} + +void IODevice_Gamepad::UpdateInput(const uint8* data, const int32 time_elapsed) +{ + buttons = (~(data[0] | (data[1] << 8))) &~ 0x3000; +} + +uint8 IODevice_Gamepad::UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) +{ + uint8 tmp; + + tmp = (buttons >> ((smpc_out >> 5) << 2)) & 0xF; + + return 0x10 | (smpc_out & (smpc_out_asserted | 0xE0)) | (tmp &~ smpc_out_asserted); +} + +} diff --git a/waterbox/ss/input/gamepad.h b/waterbox/ss/input/gamepad.h index ac2d05d9ec..99a856c487 100644 --- a/waterbox/ss/input/gamepad.h +++ b/waterbox/ss/input/gamepad.h @@ -1,48 +1,45 @@ -/******************************************************************************/ -/* Mednafen Sega Saturn Emulation Module */ -/******************************************************************************/ -/* gamepad.h: -** 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 -** 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_GAMEPAD_H -#define __MDFN_SS_INPUT_GAMEPAD_H - -namespace MDFN_IEN_SS -{ - -class IODevice_Gamepad final : public IODevice -{ - public: - IODevice_Gamepad() MDFN_COLD; - virtual ~IODevice_Gamepad() override MDFN_COLD; - - virtual void Power(void) override MDFN_COLD; - virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; - - virtual uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) override; - - private: - uint16 buttons; -}; - - -extern IDIISG IODevice_Gamepad_IDII; - -} - -#endif +/******************************************************************************/ +/* Mednafen Sega Saturn Emulation Module */ +/******************************************************************************/ +/* gamepad.h: +** 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 +** 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_GAMEPAD_H +#define __MDFN_SS_INPUT_GAMEPAD_H + +namespace MDFN_IEN_SS +{ + +class IODevice_Gamepad final : public IODevice +{ + public: + IODevice_Gamepad() MDFN_COLD; + virtual ~IODevice_Gamepad() override MDFN_COLD; + + virtual void Power(void) override MDFN_COLD; + virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; + + virtual uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) override; + + private: + uint16 buttons; +}; + +} + +#endif diff --git a/waterbox/ss/input/keyboard.cpp b/waterbox/ss/input/keyboard.cpp index 79b12ddcd8..a5aaf6aa3b 100644 --- a/waterbox/ss/input/keyboard.cpp +++ b/waterbox/ss/input/keyboard.cpp @@ -1,397 +1,231 @@ -/******************************************************************************/ -/* 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. -*/ - -// TODO: Debouncing? - -// -// 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" - -namespace MDFN_IEN_SS -{ - -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; -} - -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", gettext_noop("Off") }, - { "on", gettext_noop("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])) -}; - -} +/******************************************************************************/ +/* 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. +*/ + +// TODO: Debouncing? + +// +// 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" + +namespace MDFN_IEN_SS +{ + +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; +} + +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); +} + +} diff --git a/waterbox/ss/input/keyboard.h b/waterbox/ss/input/keyboard.h index e76f6acbcb..f6b756ba06 100644 --- a/waterbox/ss/input/keyboard.h +++ b/waterbox/ss/input/keyboard.h @@ -1,73 +1,72 @@ -/******************************************************************************/ -/* 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 - -namespace MDFN_IEN_SS -{ - -class IODevice_Keyboard final : public IODevice -{ - public: - IODevice_Keyboard() MDFN_COLD; - virtual ~IODevice_Keyboard() override MDFN_COLD; - - virtual void Power(void) override MDFN_COLD; - virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; - virtual void UpdateOutput(uint8* data) 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 +/******************************************************************************/ +/* 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 + +namespace MDFN_IEN_SS +{ + +class IODevice_Keyboard final : public IODevice +{ + public: + IODevice_Keyboard() MDFN_COLD; + virtual ~IODevice_Keyboard() override MDFN_COLD; + + virtual void Power(void) override MDFN_COLD; + virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; + virtual void UpdateOutput(uint8* data) 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; +}; + +} + +#endif diff --git a/waterbox/ss/input/mission.cpp b/waterbox/ss/input/mission.cpp index 324fc2211f..8416399a90 100644 --- a/waterbox/ss/input/mission.cpp +++ b/waterbox/ss/input/mission.cpp @@ -157,173 +157,4 @@ uint8 IODevice_Mission::UpdateBus(const uint8 smpc_out, const uint8 smpc_out_ass return (smpc_out & (smpc_out_asserted | 0xE0)) | (tmp &~ smpc_out_asserted); } -static const char* const SpeedSwitchPositions[] = -{ - gettext_noop("1/7"), - gettext_noop("2/7"), - gettext_noop("3/7"), - gettext_noop("4/7"), - gettext_noop("5/7"), - gettext_noop("6/7"), - gettext_noop("7/7") -}; - -static const char* const AFSwitchPositions[] = -{ - gettext_noop("• (Off)"), - gettext_noop("•• (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 }, - -}; - - - } diff --git a/waterbox/ss/input/mission.h b/waterbox/ss/input/mission.h index 579dc51458..0f2bf648dc 100644 --- a/waterbox/ss/input/mission.h +++ b/waterbox/ss/input/mission.h @@ -1,64 +1,58 @@ -/******************************************************************************/ -/* 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 - -namespace MDFN_IEN_SS -{ - -class IODevice_Mission final : public IODevice -{ - public: - IODevice_Mission(const bool dual_) MDFN_COLD; - virtual ~IODevice_Mission() override MDFN_COLD; - - virtual void Power(void) override MDFN_COLD; - virtual void UpdateInput(const uint8* data, const int32 time_elapsed) 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 +/******************************************************************************/ +/* 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 + +namespace MDFN_IEN_SS +{ + +class IODevice_Mission final : public IODevice +{ + public: + IODevice_Mission(const bool dual_) MDFN_COLD; + virtual ~IODevice_Mission() override MDFN_COLD; + + virtual void Power(void) override MDFN_COLD; + virtual void UpdateInput(const uint8* data, const int32 time_elapsed) 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; +}; + +} + +#endif diff --git a/waterbox/ss/input/mouse.cpp b/waterbox/ss/input/mouse.cpp index 2cfbf441b2..e56e61f3a5 100644 --- a/waterbox/ss/input/mouse.cpp +++ b/waterbox/ss/input/mouse.cpp @@ -128,16 +128,4 @@ uint8 IODevice_Mouse::UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asser return (smpc_out & (smpc_out_asserted | 0xE0)) | (tmp &~ smpc_out_asserted); } -IDIISG IODevice_Mouse_IDII = -{ - { "x_axis", "X Axis", -1, IDIT_X_AXIS_REL }, - { "y_axis", "Y Axis", -1, IDIT_Y_AXIS_REL }, - - { "left", "Left Button", 0, IDIT_BUTTON }, - { "right", "Right Button", 2, IDIT_BUTTON }, - { "middle", "Middle Button", 1, IDIT_BUTTON }, - { "start", "Start", 3, IDIT_BUTTON }, -}; - - } diff --git a/waterbox/ss/input/mouse.h b/waterbox/ss/input/mouse.h index 5968a2adbf..aa434b7943 100644 --- a/waterbox/ss/input/mouse.h +++ b/waterbox/ss/input/mouse.h @@ -1,55 +1,52 @@ -/******************************************************************************/ -/* Mednafen Sega Saturn Emulation Module */ -/******************************************************************************/ -/* mouse.h: -** 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 -** 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_MOUSE_H -#define __MDFN_SS_INPUT_MOUSE_H - -namespace MDFN_IEN_SS -{ - -class IODevice_Mouse final : public IODevice -{ - public: - IODevice_Mouse() MDFN_COLD; - virtual ~IODevice_Mouse() override MDFN_COLD; - - virtual void Power(void) override MDFN_COLD; - virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; - - virtual uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) override; - - private: - int32 accum_xdelta; - int32 accum_ydelta; - - uint8 buttons; - uint8 buffer[0x10]; - uint8 data_out; - bool tl; - int8 phase; -}; - - -extern IDIISG IODevice_Mouse_IDII; - -} - -#endif +/******************************************************************************/ +/* Mednafen Sega Saturn Emulation Module */ +/******************************************************************************/ +/* mouse.h: +** 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 +** 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_MOUSE_H +#define __MDFN_SS_INPUT_MOUSE_H + +namespace MDFN_IEN_SS +{ + +class IODevice_Mouse final : public IODevice +{ + public: + IODevice_Mouse() MDFN_COLD; + virtual ~IODevice_Mouse() override MDFN_COLD; + + virtual void Power(void) override MDFN_COLD; + virtual void UpdateInput(const uint8* data, const int32 time_elapsed) override; + + virtual uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) override; + + private: + int32 accum_xdelta; + int32 accum_ydelta; + + uint8 buttons; + uint8 buffer[0x10]; + uint8 data_out; + bool tl; + int8 phase; +}; + +} + +#endif diff --git a/waterbox/ss/input/wheel.cpp b/waterbox/ss/input/wheel.cpp index bb47175dd8..2060fedcd1 100644 --- a/waterbox/ss/input/wheel.cpp +++ b/waterbox/ss/input/wheel.cpp @@ -102,33 +102,4 @@ uint8 IODevice_Wheel::UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asser 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 }, -}; - - - - } diff --git a/waterbox/ss/input/wheel.h b/waterbox/ss/input/wheel.h index edfc23e03b..02f54dd98d 100644 --- a/waterbox/ss/input/wheel.h +++ b/waterbox/ss/input/wheel.h @@ -1,54 +1,51 @@ -/******************************************************************************/ -/* 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 - -namespace MDFN_IEN_SS -{ - -class IODevice_Wheel final : public IODevice -{ - public: - IODevice_Wheel() MDFN_COLD; - virtual ~IODevice_Wheel() override MDFN_COLD; - - virtual void Power(void) override MDFN_COLD; - virtual void UpdateInput(const uint8* data, const int32 time_elapsed) 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 +/******************************************************************************/ +/* 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 + +namespace MDFN_IEN_SS +{ + +class IODevice_Wheel final : public IODevice +{ + public: + IODevice_Wheel() MDFN_COLD; + virtual ~IODevice_Wheel() override MDFN_COLD; + + virtual void Power(void) override MDFN_COLD; + virtual void UpdateInput(const uint8* data, const int32 time_elapsed) 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; +}; + +} + +#endif diff --git a/waterbox/ss/smpc.cpp b/waterbox/ss/smpc.cpp index b61874b380..e61922eb8c 100644 --- a/waterbox/ss/smpc.cpp +++ b/waterbox/ss/smpc.cpp @@ -1,1441 +1,1441 @@ -/******************************************************************************/ -/* Mednafen Sega Saturn Emulation Module */ -/******************************************************************************/ -/* smpc.cpp - SMPC Emulation -** 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 -** 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. -*/ - -/* - TODO: - CD On/Off -*/ - -#include "ss.h" -#include "cdrom/CDUtility.h" -using namespace CDUtility; - -#include "smpc.h" -#include "sound.h" -#include "vdp1.h" -#include "vdp2.h" -#include "cdb.h" -#include "scu.h" - -#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 "input/jpkeyboard.h" - -#include "input/multitap.h" - -namespace MDFN_IEN_SS -{ -#include "sh7095.h" - -enum -{ - CLOCK_DIVISOR_26M = 65, - CLOCK_DIVISOR_28M = 61 -}; - -enum -{ - CMD_MSHON = 0x00, - CMD_SSHON = 0x02, - CMD_SSHOFF = 0x03, - - CMD_SNDON = 0x06, - CMD_SNDOFF = 0x07, - - CMD_CDON = 0x08, - CMD_CDOFF = 0x09, - - // A, B, C do something... - - CMD_SYSRES = 0x0D, - - CMD_CKCHG352 = 0x0E, - CMD_CKCHG320 = 0x0F, - - CMD_INTBACK = 0x10, - CMD_SETTIME = 0x16, - CMD_SETSMEM = 0x17, - - CMD_NMIREQ = 0x18, - CMD_RESENAB = 0x19, - CMD_RESDISA = 0x1A -}; - -static uint8 AreaCode; -static int32 MasterClock; - -static struct -{ - uint64 ClockAccum; - - bool Valid; - - union - { - uint8 raw[7]; - struct - { - uint8 year[2]; // BCD; [0] = xx00, [1] = 00xx - uint8 wday_mon; // 0x0-0x6(upper; 6=Saturday), 0x1-0xC(lower) - uint8 mday; // BCD; 0x01-0x31 - uint8 hour; // BCD; 0x00-0x23 - uint8 minute; // BCD; 0x00-0x59 - uint8 second; // BCD; 0x00-0x59 - }; - }; -} RTC; - -static uint8 SaveMem[4]; - -static uint8 IREG[7]; -static uint8 OREG[0x20]; -static uint8 SR; -static bool SF; - -enum -{ - PMODE_15BYTE = 0, - PMODE_255BYTE = 1, - PMODE_ILL = 2, - PMODE_0BYTE = 3 -}; - -enum -{ - SR_RESB = 0x10, - SR_NPE = 0x20, - SR_PDL = 0x40, -}; - -static bool ResetNMIEnable; - -static bool ResetButtonPhysStatus; -static int32 ResetButtonCount; -static bool ResetPending; -static int32 PendingCommand; -static int32 ExecutingCommand; -static int32 PendingClockDivisor; -static int32 CurrentClockDivisor; - -static bool PendingVB; - -static int32 SubPhase; -static int64 ClockCounter; -static uint32 SMPC_ClockRatio; - -static bool SoundCPUOn; -static bool SlaveSH2On; -static bool CDOn; - -static uint8 BusBuffer; -// -// -static struct -{ - int64 TimeCounter; - int32 StartTime; - int32 OptWaitUntilTime; - int32 OptEatTime; - - int32 OptReadTime; - - uint8 Mode[2]; - bool TimeOptEn; - bool NextContBit; - - uint8 CurPort; - uint8 ID1; - uint8 ID2; - uint8 IDTap; - - uint8 CommMode; - - uint8 OWP; - - uint8 work[8]; - // - // - uint8 TapCounter; - uint8 TapCount; - uint8 ReadCounter; - uint8 ReadCount; - uint8 ReadBuffer[255]; //16]; - uint8 WriteCounter; - uint8 PDCounter; -} JRS; -// -// -static uint8 DataOut[2][2]; -static uint8 DataDir[2][2]; -static bool DirectModeEn[2]; -static bool ExLatchEn[2]; - -static uint8 IOBusState[2]; -static IODevice* IOPorts[2]; - -static struct PossibleDevice -{ - IODevice none; - IODevice_Gamepad gamepad; - IODevice_3DPad threedpad; - IODevice_Mouse mouse; - IODevice_Wheel wheel; - IODevice_Mission mission;//{false}; - IODevice_Mission dualmission;//{true}; - IODevice_Keyboard keyboard; -// IODevice_Keyboard jpkeyboard; - PossibleDevice() - :mission(false), dualmission(true) - { - } -} PossibleDevices[12]; - -static IODevice_Multitap PossibleMultitaps[2]; - -static IODevice_Multitap* SPorts[2]; -static IODevice* VirtualPorts[12]; -static uint8* VirtualPortsDPtr[12]; -static uint8* MiscInputPtr; - -IODevice::IODevice() { } -IODevice::~IODevice() { } -void IODevice::Power(void) { } -void IODevice::UpdateInput(const uint8* data, const int32 time_elapsed) { } -void IODevice::UpdateOutput(uint8* data) { } -uint8 IODevice::UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) { return smpc_out; } - -// -// - -static bool vb; -static sscpu_timestamp_t lastts; - -static void UpdateIOBus(unsigned port) -{ - IOBusState[port] = IOPorts[port]->UpdateBus((DataOut[port][DirectModeEn[port]] | ~DataDir[port][DirectModeEn[port]]) & 0x7F, DataDir[port][DirectModeEn[port]]); - assert(!(IOBusState[port] & 0x80)); -} - -static void MapPorts(void) -{ - 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) -{ - assert(port < 13); - - if(port == 12) - { - MiscInputPtr = ptr; - return; - } - // - // - // - IODevice* nd = nullptr; - - 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 if(!strcmp(type, "jpkeyboard")) -// nd = &PossibleDevices[port].jpkeyboard; - else - abort(); - - VirtualPorts[port] = nd; - VirtualPortsDPtr[port] = ptr; - - MapPorts(); -} - -#if 0 -static void RTC_Reset(void) -{ - - -} -#endif - -void SMPC_LoadNV(Stream* s) -{ - RTC.Valid = s->get_u8(); - s->read(RTC.raw, sizeof(RTC.raw)); - s->read(SaveMem, sizeof(SaveMem)); -} - -void SMPC_SaveNV(Stream* s) -{ - s->put_u8(RTC.Valid); - s->write(RTC.raw, sizeof(RTC.raw)); - s->write(SaveMem, sizeof(SaveMem)); -} - -void SMPC_SetRTC(const struct tm* ht, const uint8 lang) -{ - if(!ht) - { - RTC.Valid = false; - RTC.year[0] = 0x19; - RTC.year[1] = 0x93; - RTC.wday_mon = 0x5C; - RTC.mday = 0x31; - RTC.hour = 0x23; - RTC.minute = 0x59; - RTC.second = 0x59; - - for(unsigned i = 0; i < 4; i++) - SaveMem[i] = 0x00; - } - else - { - int year_adj = ht->tm_year; - //if(year_adj >= 100) - // year_adj = 100 + ((year_adj - 100) % 28); - - RTC.Valid = true; //false; - RTC.year[0] = U8_to_BCD(19 + year_adj / 100); - RTC.year[1] = U8_to_BCD(year_adj % 100); - RTC.wday_mon = (std::min(6, ht->tm_wday) << 4) | ((std::min(11, ht->tm_mon) + 1) << 0); - RTC.mday = U8_to_BCD(std::min(31, ht->tm_mday)); - RTC.hour = U8_to_BCD(std::min(23, ht->tm_hour)); - RTC.minute = U8_to_BCD(std::min(59, ht->tm_min)); - RTC.second = U8_to_BCD(std::min(59, ht->tm_sec)); - - //if((SaveMem[3] & 0x0F) <= 0x05 || (SaveMem[3] & 0x0F) == 0xF) - SaveMem[3] = (SaveMem[3] & 0xF0) | lang; - } -} - -void SMPC_Init(const uint8 area_code_arg, const int32 master_clock_arg) -{ - AreaCode = area_code_arg; - MasterClock = master_clock_arg; - - ResetPending = false; - vb = false; - lastts = 0; - - for(unsigned sp = 0; sp < 2; sp++) - SPorts[sp] = nullptr; - - for(unsigned i = 0; i < 12; i++) - { - VirtualPorts[i] = nullptr; - SMPC_SetInput(i, "none", NULL); - } - - SMPC_SetRTC(NULL, 0); -} - -bool SMPC_IsSlaveOn(void) -{ - return SlaveSH2On; -} - -static void SlaveOn(void) -{ - SlaveSH2On = true; - CPU[1].AdjustTS(SH7095_mem_timestamp, true); - CPU[1].Reset(true); - SS_SetEventNT(&events[SS_EVENT_SH2_S_DMA], SH7095_mem_timestamp + 1); -} - -static void SlaveOff(void) -{ - SlaveSH2On = false; - CPU[1].Reset(true); - CPU[1].AdjustTS(0x7FFFFFFF, true); - SS_SetEventNT(&events[SS_EVENT_SH2_S_DMA], SS_EVENT_DISABLED_TS); -} - -static void TurnSoundCPUOn(void) -{ - SOUND_Reset68K(); - SoundCPUOn = true; - SOUND_Set68KActive(true); -} - -static void TurnSoundCPUOff(void) -{ - SOUND_Reset68K(); - SoundCPUOn = false; - SOUND_Set68KActive(false); -} - -void SMPC_Reset(bool powering_up) -{ - SlaveOff(); - TurnSoundCPUOff(); - CDOn = true; // ? false; - - ResetButtonCount = 0; - ResetNMIEnable = false; // or only on powering_up? - - CPU[0].SetNMI(true); - - memset(IREG, 0, sizeof(IREG)); - memset(OREG, 0, sizeof(OREG)); - PendingCommand = -1; - ExecutingCommand = -1; - SF = 0; - - BusBuffer = 0x00; - - for(unsigned port = 0; port < 2; port++) - { - for(unsigned sel = 0; sel < 2; sel++) - { - DataOut[port][sel] = 0; - DataDir[port][sel] = 0; - } - DirectModeEn[port] = false; - ExLatchEn[port] = false; - UpdateIOBus(port); - } - - ResetPending = false; - - PendingClockDivisor = 0; - CurrentClockDivisor = CLOCK_DIVISOR_26M; - - SubPhase = 0; - PendingVB = false; - ClockCounter = 0; - // - memset(&JRS, 0, sizeof(JRS)); -} - -int32 SMPC_StartFrame(EmulateSpecStruct* espec) -{ - if(ResetPending) - SS_Reset(false); - - if(PendingClockDivisor > 0) - { - CurrentClockDivisor = PendingClockDivisor; - PendingClockDivisor = 0; - } - - if(!SlaveSH2On) - CPU[1].AdjustTS(0x7FFFFFFF, true); - - SMPC_ClockRatio = (1ULL << 32) * 4000000 * CurrentClockDivisor / MasterClock; - SOUND_SetClockRatio((1ULL << 32) * 11289600 * CurrentClockDivisor / MasterClock); - CDB_SetClockRatio((1ULL << 32) * 11289600 * CurrentClockDivisor / MasterClock); - - return CurrentClockDivisor; -} - -void SMPC_UpdateOutput(void) -{ - for(unsigned vp = 0; vp < 12; vp++) - { - VirtualPorts[vp]->UpdateOutput(VirtualPortsDPtr[vp]); - } -} - -void SMPC_UpdateInput(const int32 time_elapsed) -{ - //printf("%8d\n", time_elapsed); - - ResetButtonPhysStatus = (bool)(*MiscInputPtr & 0x1); - for(unsigned vp = 0; vp < 12; vp++) - { - VirtualPorts[vp]->UpdateInput(VirtualPortsDPtr[vp], time_elapsed); - } -} - - -void SMPC_Write(const sscpu_timestamp_t timestamp, uint8 A, uint8 V) -{ - BusBuffer = V; - A &= 0x3F; - - SS_DBGTI(SS_DBG_SMPC_REGW, "[SMPC] Write to 0x%02x:0x%02x", A, V); - - // - // Call VDP2::Update() to prevent out-of-temporal-order calls to SMPC_Update() from here and the event system. - // - SS_SetEventNT(&events[SS_EVENT_VDP2], VDP2::Update(timestamp)); // TODO: conditionalize so we don't consume so much CPU time if a game writes continuously to SMPC ports - sscpu_timestamp_t nt = SMPC_Update(timestamp); - switch(A) - { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - 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); - } - - IREG[A] = V; - break; - - case 0x0F: - 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); - } - - 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 pending.", V, PendingCommand); - } - - PendingCommand = V; - break; - - case 0x31: - if(MDFN_UNLIKELY(SF)) - { - SS_DBGTI(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] SF port written while SF is 1."); - } - - SF = true; - break; - - // - // - // - case 0x3A: - DataOut[0][1] = V & 0x7F; - UpdateIOBus(0); - break; - - case 0x3B: - DataOut[1][1] = V & 0x7F; - UpdateIOBus(1); - break; - - case 0x3C: - DataDir[0][1] = V & 0x7F; - UpdateIOBus(0); - break; - - case 0x3D: - DataDir[1][1] = V & 0x7F; - UpdateIOBus(1); - break; - - case 0x3E: - DirectModeEn[0] = (bool)(V & 0x1); - UpdateIOBus(0); - - DirectModeEn[1] = (bool)(V & 0x2); - UpdateIOBus(1); - break; - - case 0x3F: - ExLatchEn[0] = (bool)(V & 0x1); - ExLatchEn[1] = (bool)(V & 0x2); - break; - - default: - SS_DBG(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] Unknown write of 0x%02x to 0x%02x\n", V, A); - break; - - } - - if(PendingCommand >= 0) - nt = timestamp + 1; - - SS_SetEventNT(&events[SS_EVENT_SMPC], nt); -} - -uint8 SMPC_Read(const sscpu_timestamp_t timestamp, uint8 A) -{ - uint8 ret = BusBuffer; - - A &= 0x3F; - - switch(A) - { - default: - SS_DBG(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] Unknown read from 0x%02x\n", A); - break; - - case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: - 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: - 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); - } - - ret = (OREG - 0x10)[A]; - break; - - case 0x30: - 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); - } - - ret = SR; - break; - - case 0x31: - ret &= ~0x01; - ret |= SF; - break; - - case 0x3A: - ret = (ret & 0x80) | IOBusState[0]; - break; - - case 0x3B: - ret = (ret & 0x80) | IOBusState[1]; - break; - - } - - return ret; -} - -void SMPC_ResetTS(void) -{ - lastts = 0; -} - -#define SMPC_WAIT_UNTIL_COND(cond) { \ - case __COUNTER__: \ - ClockCounter = 0; /* before if(), not after, otherwise the variable will overflow eventually. */ \ - if(!(cond)) \ - { \ - SubPhase = __COUNTER__ - SubPhaseBias - 1; \ - return timestamp + 1000; \ - } \ - } - -#define SMPC_WAIT_UNTIL_COND_TIMEOUT(cond, n) \ - { \ - ClockCounter -= (int64)(n) << 32; \ - case __COUNTER__: \ - if(!(cond) && ClockCounter < 0) \ - { \ - SubPhase = __COUNTER__ - SubPhaseBias - 1; \ - return timestamp + (-ClockCounter + SMPC_ClockRatio - 1) / SMPC_ClockRatio; \ - } \ - ClockCounter = 0; \ - } - -#define SMPC_EAT_CLOCKS(n) \ - { \ - ClockCounter -= (int64)(n) << 32; \ - case __COUNTER__: \ - if(ClockCounter < 0) \ - { \ - SubPhase = __COUNTER__ - SubPhaseBias - 1; \ - return timestamp + (-ClockCounter + SMPC_ClockRatio - 1) / SMPC_ClockRatio; \ - } \ - /*printf("%f\n", (double)ClockCounter / (1LL << 32));*/ \ - } \ - - -static unsigned RTC_BCDInc(uint8 v) -{ - unsigned tmp = v & 0xF; - - tmp++; - - if(tmp >= 0xA) - tmp += 0x06; - - tmp += v & 0xF0; - - if(tmp >= 0xA0) - tmp += 0x60; - - return tmp; -} - -static void RTC_IncTime(void) -{ - // Seconds - if(RTC.second == 0x59) - { - RTC.second = 0x00; - - // Minutes - if(RTC.minute == 0x59) - { - RTC.minute = 0x00; - - // Hours - if(RTC.hour == 0x23) - { - RTC.hour = 0x00; - - // Day of week - if(RTC.wday_mon >= 0x60) - RTC.wday_mon &= 0x0F; - else - RTC.wday_mon += 0x10; - - // - static const uint8 mdtab[0x10] = { - // Jan, Feb, Mar, Apr, May, June, July, Aug, Sept, Oct, Nov, Dec - 0x10, 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31, 0xC1, 0xF5, 0xFF - }; - const uint8 day_compare = mdtab[RTC.wday_mon & 0x0F] + ((RTC.wday_mon & 0x0F) == 0x02 && ((RTC.year[1] & 0x1F) < 0x1A) && !((RTC.year[1] + ((RTC.year[1] & 0x10) >> 3)) & 0x3)); - - // Day of month - if(RTC.mday >= day_compare) - { - RTC.mday = 0x01; - - // Month of year - if((RTC.wday_mon & 0x0F) == 0x0C) - { - RTC.wday_mon &= 0xF0; - RTC.wday_mon |= 0x01; - - // Year - unsigned tmp = RTC_BCDInc(RTC.year[1]); - RTC.year[1] = tmp; - - if(tmp >= 0x100) - RTC.year[0] = RTC_BCDInc(RTC.year[0]); - } - else - RTC.wday_mon++; - } - else - RTC.mday = RTC_BCDInc(RTC.mday); - } - else - RTC.hour = RTC_BCDInc(RTC.hour); - } - else - RTC.minute = RTC_BCDInc(RTC.minute); - } - else - RTC.second = RTC_BCDInc(RTC.second); -} - -enum { SubPhaseBias = __COUNTER__ + 1 }; -sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp) -{ - int64 clocks; - - if(MDFN_UNLIKELY(timestamp < lastts)) - { - SS_DBG(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] [BUG] timestamp(%d) < lastts(%d)\n", timestamp, lastts); - clocks = 0; - } - else - { - clocks = (int64)(timestamp - lastts) * SMPC_ClockRatio; - lastts = timestamp; - } - - ClockCounter += clocks; - RTC.ClockAccum += clocks; - JRS.TimeCounter += clocks; - - switch(SubPhase + SubPhaseBias) - { - for(;;) - { - default: - case __COUNTER__: - - SMPC_WAIT_UNTIL_COND(PendingCommand >= 0 || PendingVB); - - if(PendingVB && PendingCommand < 0) - { - PendingVB = false; - - if(JRS.OptReadTime) - JRS.OptWaitUntilTime = std::max(0, (JRS.TimeCounter >> 32) - JRS.OptReadTime - 5000); - else - JRS.OptWaitUntilTime = 0; - JRS.TimeCounter = 0; - SMPC_EAT_CLOCKS(234); - - SR &= ~SR_RESB; - if(ResetButtonPhysStatus) // FIXME: Semantics may not be right in regards to CMD_RESENAB timing. - { - SR |= SR_RESB; - if(ResetButtonCount >= 0) - { - ResetButtonCount++; - - if(ResetButtonCount >= 3) - { - ResetButtonCount = 3; - - if(ResetNMIEnable) - { - CPU[0].SetNMI(false); - CPU[0].SetNMI(true); - - ResetButtonCount = -1; - } - } - } - } - else - ResetButtonCount = 0; - - // - // Do RTC increment here - // - while(MDFN_UNLIKELY(RTC.ClockAccum >= (4000000ULL << 32))) - { - RTC_IncTime(); - RTC.ClockAccum -= (4000000ULL << 32); - } - - continue; - } - - ExecutingCommand = PendingCommand; - PendingCommand = -1; - - SMPC_EAT_CLOCKS(92); - if(ExecutingCommand < 0x20) - { - OREG[0x1F] = ExecutingCommand; - - 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(ExecutingCommand == CMD_MSHON) - { - - } - else if(ExecutingCommand == CMD_SSHON) - { - if(!SlaveSH2On) - SlaveOn(); - } - else if(ExecutingCommand == CMD_SSHOFF) - { - if(SlaveSH2On) - SlaveOff(); - } - else if(ExecutingCommand == CMD_SNDON) - { - if(!SoundCPUOn) - TurnSoundCPUOn(); - } - else if(ExecutingCommand == CMD_SNDOFF) - { - if(SoundCPUOn) - TurnSoundCPUOff(); - } - else if(ExecutingCommand == CMD_CDON) - { - CDOn = true; - } - else if(ExecutingCommand == CMD_CDOFF) - { - CDOn = false; - } - else if(ExecutingCommand == CMD_SYSRES) - { - ResetPending = true; - SMPC_WAIT_UNTIL_COND(!ResetPending); - - // TODO/FIXME(unreachable currently?): - } - else if(ExecutingCommand == CMD_CKCHG352 || ExecutingCommand == CMD_CKCHG320) - { - // Devour some time - - if(SlaveSH2On) - SlaveOff(); - - if(SoundCPUOn) - TurnSoundCPUOff(); - - SOUND_Reset(false); - VDP1::Reset(false); - VDP2::Reset(false); - SCU_Reset(false); - - // Change clock - PendingClockDivisor = (ExecutingCommand == CMD_CKCHG352) ? CLOCK_DIVISOR_28M : CLOCK_DIVISOR_26M; - - // Wait for a few vblanks - SMPC_WAIT_UNTIL_COND(!vb); - SMPC_WAIT_UNTIL_COND(vb); - SMPC_WAIT_UNTIL_COND(!vb); - SMPC_WAIT_UNTIL_COND(vb); - SMPC_WAIT_UNTIL_COND(!vb); - SMPC_WAIT_UNTIL_COND(vb); - - - // - SMPC_WAIT_UNTIL_COND(!PendingClockDivisor); - - // Send NMI to master SH-2 - CPU[0].SetNMI(false); - CPU[0].SetNMI(true); - } - 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); - - SR &= ~SR_NPE; - if(IREG[0] & 0xF) - { - SMPC_EAT_CLOCKS(952); - - OREG[0] = (RTC.Valid << 7) | (!ResetNMIEnable << 6); - - for(unsigned i = 0; i < 7; i++) - OREG[1 + i] = RTC.raw[i]; - - OREG[0x8] = 0; // TODO FIXME: Cartridge code? - OREG[0x9] = AreaCode; - OREG[0xA] = 0x24 | - ((CurrentClockDivisor == CLOCK_DIVISOR_28M) << 6) | - (SlaveSH2On << 4) | - (true << 3) | // TODO?: Master NMI - (true << 1) | // TODO?: sysres - (SoundCPUOn << 0); // sndres - - OREG[0xB] = (CDOn << 6) | (1 << 1); // cdres, TODO?: bit1 - - for(unsigned i = 0; i < 4; i++) - OREG[0xC + i] = SaveMem[i]; - - if(IREG[1] & 0x8) - SR |= SR_NPE; - - SR &= ~0x80; - SR |= 0x0F; - - SCU_SetInt(SCU_INT_SMPC, true); - SCU_SetInt(SCU_INT_SMPC, false); - } - - // Wait for !vb, wait until (IREG[0] & 0x80), time-optimization wait. - - if(IREG[1] & 0x8) - { - InputLagged = false; - if (InputCallback) - InputCallback(); - - - #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) \ - { \ - 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; \ - } - - #define JR_BS IOBusState[JRS.CurPort] - - #define JR_TH_TR(th, tr) \ - { \ - DataDir[JRS.CurPort][0] = ((th >= 0) << 6) | ((tr >= 0) << 5); \ - DataOut[JRS.CurPort][0] = (DataOut[JRS.CurPort][0] & 0x1F) | (((th) > 0) << 6) | (((tr) > 0) << 5); \ - UpdateIOBus(JRS.CurPort); \ - } - - JR_WAIT(!vb); - JRS.NextContBit = true; - if(SR & SR_NPE) - { - JR_WAIT((bool)(IREG[0] & 0x80) == JRS.NextContBit || (IREG[0] & 0x40)); - if(IREG[0] & 0x40) - { - SS_DBGTI(SS_DBG_SMPC, "[SMPC] Break"); - goto AbortJR; - } - 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; - - JRS.OptReadTime = 0; - JRS.OptEatTime = std::max(0, (JRS.OptWaitUntilTime - (JRS.TimeCounter >> 32))); - JRS.OptWaitUntilTime = 0; - - if(JRS.TimeOptEn) - { - SMPC_WAIT_UNTIL_COND_TIMEOUT(PendingVB, JRS.OptEatTime); - if(PendingVB) - { - SS_DBGTI(SS_DBG_SMPC, "[SMPC] abortjr timeopt"); - goto AbortJR; - } - SS_SetEventNT(&events[SS_EVENT_MIDSYNC], timestamp + 1); - } - - JRS.StartTime = JRS.TimeCounter >> 32; - JR_EAT(120); - JRS.OWP = 0; - for(JRS.CurPort = 0; JRS.CurPort < 2; JRS.CurPort++) - { - JR_EAT(380); - - if(JRS.Mode[JRS.CurPort] & 0x2) - continue; - - // TODO: 255-byte read size mode. - - JRS.ID1 = 0; - JR_TH_TR(1, 1); - JR_EAT(50); - JRS.work[0] = JR_BS; - JRS.ID1 |= ((((JRS.work[0] >> 3) | (JRS.work[0] >> 2)) & 1) << 3) | ((((JRS.work[0] >> 1) | (JRS.work[0] >> 0)) & 1) << 2); - - JR_TH_TR(0, 1); - JR_EAT(50); - JRS.work[1] = JR_BS; - JRS.ID1 |= ((((JRS.work[1] >> 3) | (JRS.work[1] >> 2)) & 1) << 1) | ((((JRS.work[1] >> 1) | (JRS.work[1] >> 0)) & 1) << 0); - - //printf("%02x, %02x\n", JRS.work[0], JRS.work[1]); - - if(JRS.ID1 == 0xB) - { - // Saturn digital pad. - JR_TH_TR(1, 0) - JR_EAT(50); - JRS.work[2] = JR_BS; - - JR_TH_TR(0, 0) - JR_EAT(50); - JRS.work[3] = JR_BS; - - JR_EAT(30); - - JR_WRNYB(0xF); // Multitap ID - JR_EAT(21); - - JR_WRNYB(0x1); // Number of connected devices behind multitap - JR_EAT(21); - - JR_WRNYB(0x0); // Peripheral ID-2. - JR_EAT(21); - - JR_WRNYB(0x2); // Data size. - JR_EAT(21); - - JR_WRNYB(JRS.work[1] & 0xF); - JR_EAT(21); - - JR_WRNYB(JRS.work[2] & 0xF); - JR_EAT(21); - - JR_WRNYB(JRS.work[3] & 0xF); - JR_EAT(21); - - JR_WRNYB((JRS.work[0] & 0xF) | 0x7); - JR_EAT(21); - - //JR_EAT(); - - // - // - // - } - else if(JRS.ID1 == 0x3 || JRS.ID1 == 0x5) - { - 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); - - //printf("%d, %02x %02x\n", JRS.CurPort, JRS.ID1, JRS.ID2); - - if(JRS.ID1 == 0x3) - JRS.ID2 = 0xE3; - - if((JRS.ID2 & 0xF0) == 0x40) // Multitap - { - JR_TH_TR(0, 0) - JR_EAT(50); - JR_WAIT(!(JR_BS & 0x10)); - JRS.IDTap = ((JRS.ID2 & 0xF) << 4) | (JR_BS & 0xF); - - JR_TH_TR(0, 1) - JR_EAT(50); - JR_WAIT(JR_BS & 0x10); - } - 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++; - } - // 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. - } - else - { - JR_WRNYB(0xF); - JR_WRNYB(0x0); - } - JR_EAT(26); - JR_TH_TR(-1, -1); - } - - 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); - - if(JRS.TimeOptEn) - JRS.OptReadTime = std::max(0, (JRS.TimeCounter >> 32) - JRS.StartTime); - } - AbortJR:; - // TODO: Set TH TR to inputs on abort. - } - 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); - - RTC.ClockAccum = 0; // settime resets sub-second count. - RTC.Valid = true; - - for(unsigned i = 0; i < 7; i++) - RTC.raw[i] = IREG[i]; - } - 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(ExecutingCommand == CMD_NMIREQ) - { - CPU[0].SetNMI(false); - CPU[0].SetNMI(true); - } - else if(ExecutingCommand == CMD_RESENAB) - { - ResetNMIEnable = true; - } - else if(ExecutingCommand == CMD_RESDISA) - { - ResetNMIEnable = false; - } - } - - ExecutingCommand = -1; - SF = false; - continue; - } - } -} - -void SMPC_SetVB(sscpu_timestamp_t event_timestamp, bool vb_status) -{ - if(vb ^ vb_status) - { - if(vb_status) // Going into vblank - PendingVB = true; - - SS_SetEventNT(&events[SS_EVENT_SMPC], event_timestamp + 1); - } - - vb = vb_status; -} - -/*static const std::vector InputDeviceInfoSSVPort = -{ - // None - { - "none", - "none", - NULL, - IDII_Empty - }, - - // Digital Gamepad - { - "gamepad", - "Digital Gamepad", - "Standard Saturn digital gamepad.", - IODevice_Gamepad_IDII - }, - - // 3D Gamepad - { - "3dpad", - "3D Control Pad", - "3D Control Pad", - IODevice_3DPad_IDII - }, - - // Mouse - { - "mouse", - "Mouse", - "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 - }, - -#if 0 - // Keyboard (Japanese) - { - "jpkeyboard", - "Keyboard (JP)", - "89-key Japanese keyboard.", - IODevice_JPKeyboard_IDII, - InputDeviceInfoStruct::FLAG_KEYBOARD - }, -#endif -}; - -static IDIISG IDII_Builtin = -{ - { "reset", "Reset", -1, IDIT_RESET_BUTTON }, - { "smpc_reset", "SMPC Reset", -1, IDIT_BUTTON }, -}; - -static const std::vector InputDeviceInfoBuiltin = -{ - { - "builtin", - "builtin", - NULL, - IDII_Builtin - } -}; - -const std::vector SMPC_PortInfo = -{ - { "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" }, -};*/ - - -} +/******************************************************************************/ +/* Mednafen Sega Saturn Emulation Module */ +/******************************************************************************/ +/* smpc.cpp - SMPC Emulation +** 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 +** 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. +*/ + +/* + TODO: + CD On/Off +*/ + +#include "ss.h" +#include "cdrom/CDUtility.h" +using namespace CDUtility; + +#include "smpc.h" +#include "sound.h" +#include "vdp1.h" +#include "vdp2.h" +#include "cdb.h" +#include "scu.h" + +#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 "input/jpkeyboard.h" + +#include "input/multitap.h" + +namespace MDFN_IEN_SS +{ +#include "sh7095.h" + +enum +{ + CLOCK_DIVISOR_26M = 65, + CLOCK_DIVISOR_28M = 61 +}; + +enum +{ + CMD_MSHON = 0x00, + CMD_SSHON = 0x02, + CMD_SSHOFF = 0x03, + + CMD_SNDON = 0x06, + CMD_SNDOFF = 0x07, + + CMD_CDON = 0x08, + CMD_CDOFF = 0x09, + + // A, B, C do something... + + CMD_SYSRES = 0x0D, + + CMD_CKCHG352 = 0x0E, + CMD_CKCHG320 = 0x0F, + + CMD_INTBACK = 0x10, + CMD_SETTIME = 0x16, + CMD_SETSMEM = 0x17, + + CMD_NMIREQ = 0x18, + CMD_RESENAB = 0x19, + CMD_RESDISA = 0x1A +}; + +static uint8 AreaCode; +static int32 MasterClock; + +static struct +{ + uint64 ClockAccum; + + bool Valid; + + union + { + uint8 raw[7]; + struct + { + uint8 year[2]; // BCD; [0] = xx00, [1] = 00xx + uint8 wday_mon; // 0x0-0x6(upper; 6=Saturday), 0x1-0xC(lower) + uint8 mday; // BCD; 0x01-0x31 + uint8 hour; // BCD; 0x00-0x23 + uint8 minute; // BCD; 0x00-0x59 + uint8 second; // BCD; 0x00-0x59 + }; + }; +} RTC; + +static uint8 SaveMem[4]; + +static uint8 IREG[7]; +static uint8 OREG[0x20]; +static uint8 SR; +static bool SF; + +enum +{ + PMODE_15BYTE = 0, + PMODE_255BYTE = 1, + PMODE_ILL = 2, + PMODE_0BYTE = 3 +}; + +enum +{ + SR_RESB = 0x10, + SR_NPE = 0x20, + SR_PDL = 0x40, +}; + +static bool ResetNMIEnable; + +static bool ResetButtonPhysStatus; +static int32 ResetButtonCount; +static bool ResetPending; +static int32 PendingCommand; +static int32 ExecutingCommand; +static int32 PendingClockDivisor; +static int32 CurrentClockDivisor; + +static bool PendingVB; + +static int32 SubPhase; +static int64 ClockCounter; +static uint32 SMPC_ClockRatio; + +static bool SoundCPUOn; +static bool SlaveSH2On; +static bool CDOn; + +static uint8 BusBuffer; +// +// +static struct +{ + int64 TimeCounter; + int32 StartTime; + int32 OptWaitUntilTime; + int32 OptEatTime; + + int32 OptReadTime; + + uint8 Mode[2]; + bool TimeOptEn; + bool NextContBit; + + uint8 CurPort; + uint8 ID1; + uint8 ID2; + uint8 IDTap; + + uint8 CommMode; + + uint8 OWP; + + uint8 work[8]; + // + // + uint8 TapCounter; + uint8 TapCount; + uint8 ReadCounter; + uint8 ReadCount; + uint8 ReadBuffer[255]; //16]; + uint8 WriteCounter; + uint8 PDCounter; +} JRS; +// +// +static uint8 DataOut[2][2]; +static uint8 DataDir[2][2]; +static bool DirectModeEn[2]; +static bool ExLatchEn[2]; + +static uint8 IOBusState[2]; +static IODevice* IOPorts[2]; + +static struct PossibleDevice +{ + IODevice none; + IODevice_Gamepad gamepad; + IODevice_3DPad threedpad; + IODevice_Mouse mouse; + IODevice_Wheel wheel; + IODevice_Mission mission;//{false}; + IODevice_Mission dualmission;//{true}; + IODevice_Keyboard keyboard; +// IODevice_Keyboard jpkeyboard; + PossibleDevice() + :mission(false), dualmission(true) + { + } +} PossibleDevices[12]; + +static IODevice_Multitap PossibleMultitaps[2]; + +static IODevice_Multitap* SPorts[2]; +static IODevice* VirtualPorts[12]; +static uint8* VirtualPortsDPtr[12]; +static uint8* MiscInputPtr; + +IODevice::IODevice() { } +IODevice::~IODevice() { } +void IODevice::Power(void) { } +void IODevice::UpdateInput(const uint8* data, const int32 time_elapsed) { } +void IODevice::UpdateOutput(uint8* data) { } +uint8 IODevice::UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted) { return smpc_out; } + +// +// + +static bool vb; +static sscpu_timestamp_t lastts; + +static void UpdateIOBus(unsigned port) +{ + IOBusState[port] = IOPorts[port]->UpdateBus((DataOut[port][DirectModeEn[port]] | ~DataDir[port][DirectModeEn[port]]) & 0x7F, DataDir[port][DirectModeEn[port]]); + assert(!(IOBusState[port] & 0x80)); +} + +static void MapPorts(void) +{ + 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) +{ + assert(port < 13); + + if(port == 12) + { + MiscInputPtr = ptr; + return; + } + // + // + // + IODevice* nd = nullptr; + + 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 if(!strcmp(type, "jpkeyboard")) +// nd = &PossibleDevices[port].jpkeyboard; + else + abort(); + + VirtualPorts[port] = nd; + VirtualPortsDPtr[port] = ptr; + + MapPorts(); +} + +#if 0 +static void RTC_Reset(void) +{ + + +} +#endif + +/*void SMPC_LoadNV(Stream* s) +{ + RTC.Valid = s->get_u8(); + s->read(RTC.raw, sizeof(RTC.raw)); + s->read(SaveMem, sizeof(SaveMem)); +} + +void SMPC_SaveNV(Stream* s) +{ + s->put_u8(RTC.Valid); + s->write(RTC.raw, sizeof(RTC.raw)); + s->write(SaveMem, sizeof(SaveMem)); +}*/ + +void SMPC_SetRTC(const struct tm* ht, const uint8 lang) +{ + if(!ht) + { + RTC.Valid = false; + RTC.year[0] = 0x19; + RTC.year[1] = 0x93; + RTC.wday_mon = 0x5C; + RTC.mday = 0x31; + RTC.hour = 0x23; + RTC.minute = 0x59; + RTC.second = 0x59; + + for(unsigned i = 0; i < 4; i++) + SaveMem[i] = 0x00; + } + else + { + int year_adj = ht->tm_year; + //if(year_adj >= 100) + // year_adj = 100 + ((year_adj - 100) % 28); + + RTC.Valid = true; //false; + RTC.year[0] = U8_to_BCD(19 + year_adj / 100); + RTC.year[1] = U8_to_BCD(year_adj % 100); + RTC.wday_mon = (std::min(6, ht->tm_wday) << 4) | ((std::min(11, ht->tm_mon) + 1) << 0); + RTC.mday = U8_to_BCD(std::min(31, ht->tm_mday)); + RTC.hour = U8_to_BCD(std::min(23, ht->tm_hour)); + RTC.minute = U8_to_BCD(std::min(59, ht->tm_min)); + RTC.second = U8_to_BCD(std::min(59, ht->tm_sec)); + + //if((SaveMem[3] & 0x0F) <= 0x05 || (SaveMem[3] & 0x0F) == 0xF) + SaveMem[3] = (SaveMem[3] & 0xF0) | lang; + } +} + +void SMPC_Init(const uint8 area_code_arg, const int32 master_clock_arg) +{ + AreaCode = area_code_arg; + MasterClock = master_clock_arg; + + ResetPending = false; + vb = false; + lastts = 0; + + for(unsigned sp = 0; sp < 2; sp++) + SPorts[sp] = nullptr; + + for(unsigned i = 0; i < 12; i++) + { + VirtualPorts[i] = nullptr; + SMPC_SetInput(i, "none", NULL); + } + + SMPC_SetRTC(NULL, 0); +} + +bool SMPC_IsSlaveOn(void) +{ + return SlaveSH2On; +} + +static void SlaveOn(void) +{ + SlaveSH2On = true; + CPU[1].AdjustTS(SH7095_mem_timestamp, true); + CPU[1].Reset(true); + SS_SetEventNT(&events[SS_EVENT_SH2_S_DMA], SH7095_mem_timestamp + 1); +} + +static void SlaveOff(void) +{ + SlaveSH2On = false; + CPU[1].Reset(true); + CPU[1].AdjustTS(0x7FFFFFFF, true); + SS_SetEventNT(&events[SS_EVENT_SH2_S_DMA], SS_EVENT_DISABLED_TS); +} + +static void TurnSoundCPUOn(void) +{ + SOUND_Reset68K(); + SoundCPUOn = true; + SOUND_Set68KActive(true); +} + +static void TurnSoundCPUOff(void) +{ + SOUND_Reset68K(); + SoundCPUOn = false; + SOUND_Set68KActive(false); +} + +void SMPC_Reset(bool powering_up) +{ + SlaveOff(); + TurnSoundCPUOff(); + CDOn = true; // ? false; + + ResetButtonCount = 0; + ResetNMIEnable = false; // or only on powering_up? + + CPU[0].SetNMI(true); + + memset(IREG, 0, sizeof(IREG)); + memset(OREG, 0, sizeof(OREG)); + PendingCommand = -1; + ExecutingCommand = -1; + SF = 0; + + BusBuffer = 0x00; + + for(unsigned port = 0; port < 2; port++) + { + for(unsigned sel = 0; sel < 2; sel++) + { + DataOut[port][sel] = 0; + DataDir[port][sel] = 0; + } + DirectModeEn[port] = false; + ExLatchEn[port] = false; + UpdateIOBus(port); + } + + ResetPending = false; + + PendingClockDivisor = 0; + CurrentClockDivisor = CLOCK_DIVISOR_26M; + + SubPhase = 0; + PendingVB = false; + ClockCounter = 0; + // + memset(&JRS, 0, sizeof(JRS)); +} + +int32 SMPC_StartFrame(EmulateSpecStruct* espec) +{ + if(ResetPending) + SS_Reset(false); + + if(PendingClockDivisor > 0) + { + CurrentClockDivisor = PendingClockDivisor; + PendingClockDivisor = 0; + } + + if(!SlaveSH2On) + CPU[1].AdjustTS(0x7FFFFFFF, true); + + SMPC_ClockRatio = (1ULL << 32) * 4000000 * CurrentClockDivisor / MasterClock; + SOUND_SetClockRatio((1ULL << 32) * 11289600 * CurrentClockDivisor / MasterClock); + CDB_SetClockRatio((1ULL << 32) * 11289600 * CurrentClockDivisor / MasterClock); + + return CurrentClockDivisor; +} + +void SMPC_UpdateOutput(void) +{ + for(unsigned vp = 0; vp < 12; vp++) + { + VirtualPorts[vp]->UpdateOutput(VirtualPortsDPtr[vp]); + } +} + +void SMPC_UpdateInput(const int32 time_elapsed) +{ + //printf("%8d\n", time_elapsed); + + ResetButtonPhysStatus = (bool)(*MiscInputPtr & 0x1); + for(unsigned vp = 0; vp < 12; vp++) + { + VirtualPorts[vp]->UpdateInput(VirtualPortsDPtr[vp], time_elapsed); + } +} + + +void SMPC_Write(const sscpu_timestamp_t timestamp, uint8 A, uint8 V) +{ + BusBuffer = V; + A &= 0x3F; + + SS_DBGTI(SS_DBG_SMPC_REGW, "[SMPC] Write to 0x%02x:0x%02x", A, V); + + // + // Call VDP2::Update() to prevent out-of-temporal-order calls to SMPC_Update() from here and the event system. + // + SS_SetEventNT(&events[SS_EVENT_VDP2], VDP2::Update(timestamp)); // TODO: conditionalize so we don't consume so much CPU time if a game writes continuously to SMPC ports + sscpu_timestamp_t nt = SMPC_Update(timestamp); + switch(A) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + 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); + } + + IREG[A] = V; + break; + + case 0x0F: + 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); + } + + 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 pending.", V, PendingCommand); + } + + PendingCommand = V; + break; + + case 0x31: + if(MDFN_UNLIKELY(SF)) + { + SS_DBGTI(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] SF port written while SF is 1."); + } + + SF = true; + break; + + // + // + // + case 0x3A: + DataOut[0][1] = V & 0x7F; + UpdateIOBus(0); + break; + + case 0x3B: + DataOut[1][1] = V & 0x7F; + UpdateIOBus(1); + break; + + case 0x3C: + DataDir[0][1] = V & 0x7F; + UpdateIOBus(0); + break; + + case 0x3D: + DataDir[1][1] = V & 0x7F; + UpdateIOBus(1); + break; + + case 0x3E: + DirectModeEn[0] = (bool)(V & 0x1); + UpdateIOBus(0); + + DirectModeEn[1] = (bool)(V & 0x2); + UpdateIOBus(1); + break; + + case 0x3F: + ExLatchEn[0] = (bool)(V & 0x1); + ExLatchEn[1] = (bool)(V & 0x2); + break; + + default: + SS_DBG(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] Unknown write of 0x%02x to 0x%02x\n", V, A); + break; + + } + + if(PendingCommand >= 0) + nt = timestamp + 1; + + SS_SetEventNT(&events[SS_EVENT_SMPC], nt); +} + +uint8 SMPC_Read(const sscpu_timestamp_t timestamp, uint8 A) +{ + uint8 ret = BusBuffer; + + A &= 0x3F; + + switch(A) + { + default: + SS_DBG(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] Unknown read from 0x%02x\n", A); + break; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: + 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: + 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); + } + + ret = (OREG - 0x10)[A]; + break; + + case 0x30: + 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); + } + + ret = SR; + break; + + case 0x31: + ret &= ~0x01; + ret |= SF; + break; + + case 0x3A: + ret = (ret & 0x80) | IOBusState[0]; + break; + + case 0x3B: + ret = (ret & 0x80) | IOBusState[1]; + break; + + } + + return ret; +} + +void SMPC_ResetTS(void) +{ + lastts = 0; +} + +#define SMPC_WAIT_UNTIL_COND(cond) { \ + case __COUNTER__: \ + ClockCounter = 0; /* before if(), not after, otherwise the variable will overflow eventually. */ \ + if(!(cond)) \ + { \ + SubPhase = __COUNTER__ - SubPhaseBias - 1; \ + return timestamp + 1000; \ + } \ + } + +#define SMPC_WAIT_UNTIL_COND_TIMEOUT(cond, n) \ + { \ + ClockCounter -= (int64)(n) << 32; \ + case __COUNTER__: \ + if(!(cond) && ClockCounter < 0) \ + { \ + SubPhase = __COUNTER__ - SubPhaseBias - 1; \ + return timestamp + (-ClockCounter + SMPC_ClockRatio - 1) / SMPC_ClockRatio; \ + } \ + ClockCounter = 0; \ + } + +#define SMPC_EAT_CLOCKS(n) \ + { \ + ClockCounter -= (int64)(n) << 32; \ + case __COUNTER__: \ + if(ClockCounter < 0) \ + { \ + SubPhase = __COUNTER__ - SubPhaseBias - 1; \ + return timestamp + (-ClockCounter + SMPC_ClockRatio - 1) / SMPC_ClockRatio; \ + } \ + /*printf("%f\n", (double)ClockCounter / (1LL << 32));*/ \ + } \ + + +static unsigned RTC_BCDInc(uint8 v) +{ + unsigned tmp = v & 0xF; + + tmp++; + + if(tmp >= 0xA) + tmp += 0x06; + + tmp += v & 0xF0; + + if(tmp >= 0xA0) + tmp += 0x60; + + return tmp; +} + +static void RTC_IncTime(void) +{ + // Seconds + if(RTC.second == 0x59) + { + RTC.second = 0x00; + + // Minutes + if(RTC.minute == 0x59) + { + RTC.minute = 0x00; + + // Hours + if(RTC.hour == 0x23) + { + RTC.hour = 0x00; + + // Day of week + if(RTC.wday_mon >= 0x60) + RTC.wday_mon &= 0x0F; + else + RTC.wday_mon += 0x10; + + // + static const uint8 mdtab[0x10] = { + // Jan, Feb, Mar, Apr, May, June, July, Aug, Sept, Oct, Nov, Dec + 0x10, 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31, 0xC1, 0xF5, 0xFF + }; + const uint8 day_compare = mdtab[RTC.wday_mon & 0x0F] + ((RTC.wday_mon & 0x0F) == 0x02 && ((RTC.year[1] & 0x1F) < 0x1A) && !((RTC.year[1] + ((RTC.year[1] & 0x10) >> 3)) & 0x3)); + + // Day of month + if(RTC.mday >= day_compare) + { + RTC.mday = 0x01; + + // Month of year + if((RTC.wday_mon & 0x0F) == 0x0C) + { + RTC.wday_mon &= 0xF0; + RTC.wday_mon |= 0x01; + + // Year + unsigned tmp = RTC_BCDInc(RTC.year[1]); + RTC.year[1] = tmp; + + if(tmp >= 0x100) + RTC.year[0] = RTC_BCDInc(RTC.year[0]); + } + else + RTC.wday_mon++; + } + else + RTC.mday = RTC_BCDInc(RTC.mday); + } + else + RTC.hour = RTC_BCDInc(RTC.hour); + } + else + RTC.minute = RTC_BCDInc(RTC.minute); + } + else + RTC.second = RTC_BCDInc(RTC.second); +} + +enum { SubPhaseBias = __COUNTER__ + 1 }; +sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp) +{ + int64 clocks; + + if(MDFN_UNLIKELY(timestamp < lastts)) + { + SS_DBG(SS_DBG_WARNING | SS_DBG_SMPC, "[SMPC] [BUG] timestamp(%d) < lastts(%d)\n", timestamp, lastts); + clocks = 0; + } + else + { + clocks = (int64)(timestamp - lastts) * SMPC_ClockRatio; + lastts = timestamp; + } + + ClockCounter += clocks; + RTC.ClockAccum += clocks; + JRS.TimeCounter += clocks; + + switch(SubPhase + SubPhaseBias) + { + for(;;) + { + default: + case __COUNTER__: + + SMPC_WAIT_UNTIL_COND(PendingCommand >= 0 || PendingVB); + + if(PendingVB && PendingCommand < 0) + { + PendingVB = false; + + if(JRS.OptReadTime) + JRS.OptWaitUntilTime = std::max(0, (JRS.TimeCounter >> 32) - JRS.OptReadTime - 5000); + else + JRS.OptWaitUntilTime = 0; + JRS.TimeCounter = 0; + SMPC_EAT_CLOCKS(234); + + SR &= ~SR_RESB; + if(ResetButtonPhysStatus) // FIXME: Semantics may not be right in regards to CMD_RESENAB timing. + { + SR |= SR_RESB; + if(ResetButtonCount >= 0) + { + ResetButtonCount++; + + if(ResetButtonCount >= 3) + { + ResetButtonCount = 3; + + if(ResetNMIEnable) + { + CPU[0].SetNMI(false); + CPU[0].SetNMI(true); + + ResetButtonCount = -1; + } + } + } + } + else + ResetButtonCount = 0; + + // + // Do RTC increment here + // + while(MDFN_UNLIKELY(RTC.ClockAccum >= (4000000ULL << 32))) + { + RTC_IncTime(); + RTC.ClockAccum -= (4000000ULL << 32); + } + + continue; + } + + ExecutingCommand = PendingCommand; + PendingCommand = -1; + + SMPC_EAT_CLOCKS(92); + if(ExecutingCommand < 0x20) + { + OREG[0x1F] = ExecutingCommand; + + 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(ExecutingCommand == CMD_MSHON) + { + + } + else if(ExecutingCommand == CMD_SSHON) + { + if(!SlaveSH2On) + SlaveOn(); + } + else if(ExecutingCommand == CMD_SSHOFF) + { + if(SlaveSH2On) + SlaveOff(); + } + else if(ExecutingCommand == CMD_SNDON) + { + if(!SoundCPUOn) + TurnSoundCPUOn(); + } + else if(ExecutingCommand == CMD_SNDOFF) + { + if(SoundCPUOn) + TurnSoundCPUOff(); + } + else if(ExecutingCommand == CMD_CDON) + { + CDOn = true; + } + else if(ExecutingCommand == CMD_CDOFF) + { + CDOn = false; + } + else if(ExecutingCommand == CMD_SYSRES) + { + ResetPending = true; + SMPC_WAIT_UNTIL_COND(!ResetPending); + + // TODO/FIXME(unreachable currently?): + } + else if(ExecutingCommand == CMD_CKCHG352 || ExecutingCommand == CMD_CKCHG320) + { + // Devour some time + + if(SlaveSH2On) + SlaveOff(); + + if(SoundCPUOn) + TurnSoundCPUOff(); + + SOUND_Reset(false); + VDP1::Reset(false); + VDP2::Reset(false); + SCU_Reset(false); + + // Change clock + PendingClockDivisor = (ExecutingCommand == CMD_CKCHG352) ? CLOCK_DIVISOR_28M : CLOCK_DIVISOR_26M; + + // Wait for a few vblanks + SMPC_WAIT_UNTIL_COND(!vb); + SMPC_WAIT_UNTIL_COND(vb); + SMPC_WAIT_UNTIL_COND(!vb); + SMPC_WAIT_UNTIL_COND(vb); + SMPC_WAIT_UNTIL_COND(!vb); + SMPC_WAIT_UNTIL_COND(vb); + + + // + SMPC_WAIT_UNTIL_COND(!PendingClockDivisor); + + // Send NMI to master SH-2 + CPU[0].SetNMI(false); + CPU[0].SetNMI(true); + } + 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); + + SR &= ~SR_NPE; + if(IREG[0] & 0xF) + { + SMPC_EAT_CLOCKS(952); + + OREG[0] = (RTC.Valid << 7) | (!ResetNMIEnable << 6); + + for(unsigned i = 0; i < 7; i++) + OREG[1 + i] = RTC.raw[i]; + + OREG[0x8] = 0; // TODO FIXME: Cartridge code? + OREG[0x9] = AreaCode; + OREG[0xA] = 0x24 | + ((CurrentClockDivisor == CLOCK_DIVISOR_28M) << 6) | + (SlaveSH2On << 4) | + (true << 3) | // TODO?: Master NMI + (true << 1) | // TODO?: sysres + (SoundCPUOn << 0); // sndres + + OREG[0xB] = (CDOn << 6) | (1 << 1); // cdres, TODO?: bit1 + + for(unsigned i = 0; i < 4; i++) + OREG[0xC + i] = SaveMem[i]; + + if(IREG[1] & 0x8) + SR |= SR_NPE; + + SR &= ~0x80; + SR |= 0x0F; + + SCU_SetInt(SCU_INT_SMPC, true); + SCU_SetInt(SCU_INT_SMPC, false); + } + + // Wait for !vb, wait until (IREG[0] & 0x80), time-optimization wait. + + if(IREG[1] & 0x8) + { + InputLagged = false; + if (InputCallback) + InputCallback(); + + + #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) \ + { \ + 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; \ + } + + #define JR_BS IOBusState[JRS.CurPort] + + #define JR_TH_TR(th, tr) \ + { \ + DataDir[JRS.CurPort][0] = ((th >= 0) << 6) | ((tr >= 0) << 5); \ + DataOut[JRS.CurPort][0] = (DataOut[JRS.CurPort][0] & 0x1F) | (((th) > 0) << 6) | (((tr) > 0) << 5); \ + UpdateIOBus(JRS.CurPort); \ + } + + JR_WAIT(!vb); + JRS.NextContBit = true; + if(SR & SR_NPE) + { + JR_WAIT((bool)(IREG[0] & 0x80) == JRS.NextContBit || (IREG[0] & 0x40)); + if(IREG[0] & 0x40) + { + SS_DBGTI(SS_DBG_SMPC, "[SMPC] Break"); + goto AbortJR; + } + 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; + + JRS.OptReadTime = 0; + JRS.OptEatTime = std::max(0, (JRS.OptWaitUntilTime - (JRS.TimeCounter >> 32))); + JRS.OptWaitUntilTime = 0; + + if(JRS.TimeOptEn) + { + SMPC_WAIT_UNTIL_COND_TIMEOUT(PendingVB, JRS.OptEatTime); + if(PendingVB) + { + SS_DBGTI(SS_DBG_SMPC, "[SMPC] abortjr timeopt"); + goto AbortJR; + } + SS_SetEventNT(&events[SS_EVENT_MIDSYNC], timestamp + 1); + } + + JRS.StartTime = JRS.TimeCounter >> 32; + JR_EAT(120); + JRS.OWP = 0; + for(JRS.CurPort = 0; JRS.CurPort < 2; JRS.CurPort++) + { + JR_EAT(380); + + if(JRS.Mode[JRS.CurPort] & 0x2) + continue; + + // TODO: 255-byte read size mode. + + JRS.ID1 = 0; + JR_TH_TR(1, 1); + JR_EAT(50); + JRS.work[0] = JR_BS; + JRS.ID1 |= ((((JRS.work[0] >> 3) | (JRS.work[0] >> 2)) & 1) << 3) | ((((JRS.work[0] >> 1) | (JRS.work[0] >> 0)) & 1) << 2); + + JR_TH_TR(0, 1); + JR_EAT(50); + JRS.work[1] = JR_BS; + JRS.ID1 |= ((((JRS.work[1] >> 3) | (JRS.work[1] >> 2)) & 1) << 1) | ((((JRS.work[1] >> 1) | (JRS.work[1] >> 0)) & 1) << 0); + + //printf("%02x, %02x\n", JRS.work[0], JRS.work[1]); + + if(JRS.ID1 == 0xB) + { + // Saturn digital pad. + JR_TH_TR(1, 0) + JR_EAT(50); + JRS.work[2] = JR_BS; + + JR_TH_TR(0, 0) + JR_EAT(50); + JRS.work[3] = JR_BS; + + JR_EAT(30); + + JR_WRNYB(0xF); // Multitap ID + JR_EAT(21); + + JR_WRNYB(0x1); // Number of connected devices behind multitap + JR_EAT(21); + + JR_WRNYB(0x0); // Peripheral ID-2. + JR_EAT(21); + + JR_WRNYB(0x2); // Data size. + JR_EAT(21); + + JR_WRNYB(JRS.work[1] & 0xF); + JR_EAT(21); + + JR_WRNYB(JRS.work[2] & 0xF); + JR_EAT(21); + + JR_WRNYB(JRS.work[3] & 0xF); + JR_EAT(21); + + JR_WRNYB((JRS.work[0] & 0xF) | 0x7); + JR_EAT(21); + + //JR_EAT(); + + // + // + // + } + else if(JRS.ID1 == 0x3 || JRS.ID1 == 0x5) + { + 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); + + //printf("%d, %02x %02x\n", JRS.CurPort, JRS.ID1, JRS.ID2); + + if(JRS.ID1 == 0x3) + JRS.ID2 = 0xE3; + + if((JRS.ID2 & 0xF0) == 0x40) // Multitap + { + JR_TH_TR(0, 0) + JR_EAT(50); + JR_WAIT(!(JR_BS & 0x10)); + JRS.IDTap = ((JRS.ID2 & 0xF) << 4) | (JR_BS & 0xF); + + JR_TH_TR(0, 1) + JR_EAT(50); + JR_WAIT(JR_BS & 0x10); + } + 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++; + } + // 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. + } + else + { + JR_WRNYB(0xF); + JR_WRNYB(0x0); + } + JR_EAT(26); + JR_TH_TR(-1, -1); + } + + 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); + + if(JRS.TimeOptEn) + JRS.OptReadTime = std::max(0, (JRS.TimeCounter >> 32) - JRS.StartTime); + } + AbortJR:; + // TODO: Set TH TR to inputs on abort. + } + 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); + + RTC.ClockAccum = 0; // settime resets sub-second count. + RTC.Valid = true; + + for(unsigned i = 0; i < 7; i++) + RTC.raw[i] = IREG[i]; + } + 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(ExecutingCommand == CMD_NMIREQ) + { + CPU[0].SetNMI(false); + CPU[0].SetNMI(true); + } + else if(ExecutingCommand == CMD_RESENAB) + { + ResetNMIEnable = true; + } + else if(ExecutingCommand == CMD_RESDISA) + { + ResetNMIEnable = false; + } + } + + ExecutingCommand = -1; + SF = false; + continue; + } + } +} + +void SMPC_SetVB(sscpu_timestamp_t event_timestamp, bool vb_status) +{ + if(vb ^ vb_status) + { + if(vb_status) // Going into vblank + PendingVB = true; + + SS_SetEventNT(&events[SS_EVENT_SMPC], event_timestamp + 1); + } + + vb = vb_status; +} + +/*static const std::vector InputDeviceInfoSSVPort = +{ + // None + { + "none", + "none", + NULL, + IDII_Empty + }, + + // Digital Gamepad + { + "gamepad", + "Digital Gamepad", + "Standard Saturn digital gamepad.", + IODevice_Gamepad_IDII + }, + + // 3D Gamepad + { + "3dpad", + "3D Control Pad", + "3D Control Pad", + IODevice_3DPad_IDII + }, + + // Mouse + { + "mouse", + "Mouse", + "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 + }, + +#if 0 + // Keyboard (Japanese) + { + "jpkeyboard", + "Keyboard (JP)", + "89-key Japanese keyboard.", + IODevice_JPKeyboard_IDII, + InputDeviceInfoStruct::FLAG_KEYBOARD + }, +#endif +}; + +static IDIISG IDII_Builtin = +{ + { "reset", "Reset", -1, IDIT_RESET_BUTTON }, + { "smpc_reset", "SMPC Reset", -1, IDIT_BUTTON }, +}; + +static const std::vector InputDeviceInfoBuiltin = +{ + { + "builtin", + "builtin", + NULL, + IDII_Builtin + } +}; + +const std::vector SMPC_PortInfo = +{ + { "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" }, +};*/ + + +} diff --git a/waterbox/ss/smpc.h b/waterbox/ss/smpc.h index be877ce717..2076890baa 100644 --- a/waterbox/ss/smpc.h +++ b/waterbox/ss/smpc.h @@ -1,100 +1,100 @@ -/******************************************************************************/ -/* Mednafen Sega Saturn Emulation Module */ -/******************************************************************************/ -/* smpc.h: -** 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 -** 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_SMPC_H -#define __MDFN_SS_SMPC_H - -#include - -namespace MDFN_IEN_SS -{ - -enum -{ - SMPC_AREA_JP = 0x1, - SMPC_AREA_ASIA_NTSC = 0x2, - SMPC_AREA_NA = 0x4, - SMPC_AREA_CSA_NTSC = 0x5, - SMPC_AREA_KR = 0x6, - - SMPC_AREA_ASIA_PAL = 0xA, - SMPC_AREA_EU_PAL = 0xC, - SMPC_AREA_CSA_PAL = 0xD, - // - // - // - SMPC_AREA__PAL_MASK = 0x8 -}; - -enum -{ - SMPC_RTC_LANG_ENGLISH = 0, - SMPC_RTC_LANG_GERMAN = 1, - SMPC_RTC_LANG_FRENCH = 2, - SMPC_RTC_LANG_SPANISH = 3, - SMPC_RTC_LANG_ITALIAN = 4, - SMPC_RTC_LANG_JAPANESE = 5, -}; - -void SMPC_Init(const uint8 area_code, const int32 master_clock) MDFN_COLD; -bool SMPC_IsSlaveOn(void); -void SMPC_Reset(bool powering_up) MDFN_COLD; -void SMPC_LoadNV(Stream* s) MDFN_COLD; -void SMPC_SaveNV(Stream* s) MDFN_COLD; - -void SMPC_SetRTC(const struct tm* ht, const uint8 lang) MDFN_COLD; - -void SMPC_Write(const sscpu_timestamp_t timestamp, uint8 A, uint8 V) MDFN_HOT; -uint8 SMPC_Read(const sscpu_timestamp_t timestamp, uint8 A) MDFN_HOT; - -sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp); -void SMPC_ResetTS(void); - -int32 SMPC_StartFrame(EmulateSpecStruct* espec); -void SMPC_UpdateInput(const int32 time_elapsed); -void SMPC_UpdateOutput(void); -void SMPC_SetInput(unsigned port, const char* type, uint8* ptr) MDFN_COLD; -void SMPC_SetMultitap(unsigned sport, bool enabled) MDFN_COLD; - -void SMPC_SetVB(sscpu_timestamp_t event_timestamp, bool vb_status); - -class IODevice -{ - public: - - IODevice() MDFN_COLD; - virtual ~IODevice() MDFN_COLD; - - virtual void Power(void) MDFN_COLD; - - // - // 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 uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted); -}; - -//extern const std::vector SMPC_PortInfo; - -} -#endif +/******************************************************************************/ +/* Mednafen Sega Saturn Emulation Module */ +/******************************************************************************/ +/* smpc.h: +** 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 +** 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_SMPC_H +#define __MDFN_SS_SMPC_H + +#include + +namespace MDFN_IEN_SS +{ + +enum +{ + SMPC_AREA_JP = 0x1, + SMPC_AREA_ASIA_NTSC = 0x2, + SMPC_AREA_NA = 0x4, + SMPC_AREA_CSA_NTSC = 0x5, + SMPC_AREA_KR = 0x6, + + SMPC_AREA_ASIA_PAL = 0xA, + SMPC_AREA_EU_PAL = 0xC, + SMPC_AREA_CSA_PAL = 0xD, + // + // + // + SMPC_AREA__PAL_MASK = 0x8 +}; + +enum +{ + SMPC_RTC_LANG_ENGLISH = 0, + SMPC_RTC_LANG_GERMAN = 1, + SMPC_RTC_LANG_FRENCH = 2, + SMPC_RTC_LANG_SPANISH = 3, + SMPC_RTC_LANG_ITALIAN = 4, + SMPC_RTC_LANG_JAPANESE = 5, +}; + +void SMPC_Init(const uint8 area_code, const int32 master_clock) MDFN_COLD; +bool SMPC_IsSlaveOn(void); +void SMPC_Reset(bool powering_up) MDFN_COLD; +//void SMPC_LoadNV(Stream* s) MDFN_COLD; +//void SMPC_SaveNV(Stream* s) MDFN_COLD; + +void SMPC_SetRTC(const struct tm* ht, const uint8 lang) MDFN_COLD; + +void SMPC_Write(const sscpu_timestamp_t timestamp, uint8 A, uint8 V) MDFN_HOT; +uint8 SMPC_Read(const sscpu_timestamp_t timestamp, uint8 A) MDFN_HOT; + +sscpu_timestamp_t SMPC_Update(sscpu_timestamp_t timestamp); +void SMPC_ResetTS(void); + +int32 SMPC_StartFrame(EmulateSpecStruct* espec); +void SMPC_UpdateInput(const int32 time_elapsed); +void SMPC_UpdateOutput(void); +void SMPC_SetInput(unsigned port, const char* type, uint8* ptr) MDFN_COLD; +void SMPC_SetMultitap(unsigned sport, bool enabled) MDFN_COLD; + +void SMPC_SetVB(sscpu_timestamp_t event_timestamp, bool vb_status); + +class IODevice +{ + public: + + IODevice() MDFN_COLD; + virtual ~IODevice() MDFN_COLD; + + virtual void Power(void) MDFN_COLD; + + // + // 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 uint8 UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted); +}; + +//extern const std::vector SMPC_PortInfo; + +} +#endif diff --git a/waterbox/ss/ss.cpp b/waterbox/ss/ss.cpp index 82ea3e884e..ec0cf755ac 100644 --- a/waterbox/ss/ss.cpp +++ b/waterbox/ss/ss.cpp @@ -21,22 +21,10 @@ // WARNING: Be careful with 32-bit access to 16-bit space, bus locking, etc. in respect to DMA and event updates(and where they can occur). -/*#include -#include -#include -#include -#include -#include -#include */ - #include #include -//#include - -//extern MDFNGI EmulatedSS; - #include "ss.h" #include "cdrom/cdromif.h" #include "sound.h" diff --git a/waterbox/ss/stream/MemoryStream.cpp b/waterbox/ss/stream/MemoryStream.cpp deleted file mode 100644 index e0094ee128..0000000000 --- a/waterbox/ss/stream/MemoryStream.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/******************************************************************************/ -/* Mednafen - Multi-system Emulator */ -/******************************************************************************/ -/* MemoryStream.cpp: -** Copyright (C) 2012-2016 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 "ss.h" -#include "MemoryStream.h" -#include "math_ops.h" -#include - -/* - TODO: Copy and assignment constructor fixes. - - Proper negative position behavior? -*/ - -MemoryStream::MemoryStream() : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0) -{ - data_buffer_size = 0; - data_buffer_alloced = 64; - if(!(data_buffer = (uint8*)realloc(data_buffer, data_buffer_alloced))) - abort();//throw MDFN_Error(ErrnoHolder(errno)); -} - -MemoryStream::MemoryStream(uint64 alloc_hint, int alloc_hint_is_size) : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0) -{ - if(alloc_hint_is_size != 0) - { - data_buffer_size = alloc_hint; - data_buffer_alloced = alloc_hint; - - if(alloc_hint > SIZE_MAX) - abort();//throw MDFN_Error(ErrnoHolder(ENOMEM)); - } - else - { - data_buffer_size = 0; - data_buffer_alloced = (alloc_hint > SIZE_MAX) ? SIZE_MAX : alloc_hint; - } - - data_buffer_alloced = std::max(data_buffer_alloced, 1); - - if(!(data_buffer = (uint8*)realloc(data_buffer, data_buffer_alloced))) - abort();//throw MDFN_Error(ErrnoHolder(errno)); - - if(alloc_hint_is_size > 0) - memset(data_buffer, 0, data_buffer_size); -} - -MemoryStream::MemoryStream(Stream *stream, uint64 size_limit) : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0) -{ - if((position = stream->tell()) != 0) - stream->seek(0, SEEK_SET); - - void* tp; - data_buffer_size = data_buffer_alloced = stream->alloc_and_read(&tp, size_limit); - data_buffer = (uint8*)tp; - stream->close(); - delete stream; -} - -MemoryStream::MemoryStream(const MemoryStream &zs) -{ - data_buffer_size = zs.data_buffer_size; - data_buffer_alloced = zs.data_buffer_alloced; - if(!(data_buffer = (uint8*)malloc(data_buffer_alloced))) - abort();//throw MDFN_Error(ErrnoHolder(errno)); - - memcpy(data_buffer, zs.data_buffer, data_buffer_size); - - position = zs.position; -} - -#if 0 -MemoryStream & MemoryStream::operator=(const MemoryStream &zs) -{ - if(this != &zs) - { - if(data_buffer) - { - free(data_buffer); - data_buffer = NULL; - } - - data_buffer_size = zs.data_buffer_size; - data_buffer_alloced = zs.data_buffer_alloced; - - if(!(data_buffer = (uint8*)malloc(data_buffer_alloced))) - throw MDFN_Error(ErrnoHolder(errno)); - - memcpy(data_buffer, zs.data_buffer, data_buffer_size); - - position = zs.position; - } - return(*this); -} -#endif - -MemoryStream::~MemoryStream() -{ - close(); -} - -uint64 MemoryStream::attributes(void) -{ - return (ATTRIBUTE_READABLE | ATTRIBUTE_WRITEABLE | ATTRIBUTE_SEEKABLE); -} - - -uint8 *MemoryStream::map(void) noexcept -{ - return data_buffer; -} - -uint64 MemoryStream::map_size(void) noexcept -{ - return data_buffer_size; -} - -void MemoryStream::unmap(void) noexcept -{ - -} - - -INLINE void MemoryStream::grow_if_necessary(uint64 new_required_size, uint64 hole_end) -{ - if(new_required_size > data_buffer_size) - { - const uint64 old_data_buffer_size = data_buffer_size; - - if(new_required_size > data_buffer_alloced) - { - uint64 new_required_alloced = round_up_pow2(new_required_size); - uint8 *new_data_buffer; - - // first condition will happen at new_required_size > (1ULL << 63) due to round_up_pow2() "wrapping". - // second condition can occur when running on a 32-bit system. - if(new_required_alloced < new_required_size || new_required_alloced > SIZE_MAX) - new_required_alloced = SIZE_MAX; - - // If constrained alloc size isn't enough, throw an out-of-memory/address-space type error. - if(new_required_alloced < new_required_size) - abort();//throw MDFN_Error(ErrnoHolder(ENOMEM)); - - if(!(new_data_buffer = (uint8*)realloc(data_buffer, new_required_alloced))) - abort();//throw MDFN_Error(ErrnoHolder(errno)); - - // - // Assign all in one go after the realloc() so we don't leave our object in an inconsistent state if the realloc() fails. - // - data_buffer = new_data_buffer; - data_buffer_size = new_required_size; - data_buffer_alloced = new_required_alloced; - } - else - data_buffer_size = new_required_size; - - if(hole_end > old_data_buffer_size) - memset(data_buffer + old_data_buffer_size, 0, hole_end - old_data_buffer_size); - } -} - -void MemoryStream::shrink_to_fit(void) noexcept -{ - if(data_buffer_alloced > data_buffer_size) - { - uint8 *new_data_buffer; - const uint64 new_data_buffer_alloced = std::max(data_buffer_size, 1); - - new_data_buffer = (uint8*)realloc(data_buffer, new_data_buffer_alloced); - - if(new_data_buffer != NULL) - { - data_buffer = new_data_buffer; - data_buffer_alloced = new_data_buffer_alloced; - } - } -} - -uint64 MemoryStream::read(void *data, uint64 count, bool error_on_eos) -{ - //printf("%llu %llu %llu\n", position, count, data_buffer_size); - - if(count > data_buffer_size) - { - if(error_on_eos) - abort();//throw MDFN_Error(0, _("Unexpected EOF")); - - count = data_buffer_size; - } - - if(position > (data_buffer_size - count)) - { - if(error_on_eos) - abort();//throw MDFN_Error(0, _("Unexpected EOF")); - - if(data_buffer_size > position) - count = data_buffer_size - position; - else - count = 0; - } - - memmove(data, &data_buffer[position], count); - position += count; - - return count; -} - -void MemoryStream::write(const void *data, uint64 count) -{ - uint64 nrs = position + count; - - if(nrs < position) - abort();//throw MDFN_Error(ErrnoHolder(EFBIG)); - - grow_if_necessary(nrs, position); - - memmove(&data_buffer[position], data, count); - position += count; -} - -// -// Don't add code to reduce the amount of memory allocated(when possible) without providing a -// per-stream setting to disable that behavior. -// -void MemoryStream::truncate(uint64 length) -{ - grow_if_necessary(length, length); - - data_buffer_size = length; -} - -void MemoryStream::seek(int64 offset, int whence) -{ - uint64 new_position; - - switch(whence) - { - default: - abort();//throw MDFN_Error(ErrnoHolder(EINVAL)); - break; - - case SEEK_SET: - new_position = offset; - break; - - case SEEK_CUR: - new_position = position + offset; - break; - - case SEEK_END: - new_position = data_buffer_size + offset; - break; - } - - if(new_position < 0) - abort();//throw MDFN_Error(ErrnoHolder(EINVAL)); - - position = new_position; -} - -uint64 MemoryStream::tell(void) -{ - return position; -} - -uint64 MemoryStream::size(void) -{ - return data_buffer_size; -} - -void MemoryStream::flush(void) -{ - -} - -void MemoryStream::close(void) -{ - if(data_buffer) - { - free(data_buffer); - data_buffer = NULL; - } - - data_buffer_size = 0; - data_buffer_alloced = 0; - position = 0; -} - - -int MemoryStream::get_line(std::string &str) -{ - str.clear(); // or str.resize(0)?? - - while((uint64)position < data_buffer_size) - { - uint8 c = data_buffer[position++]; - - if(c == '\r' || c == '\n' || c == 0) - return(c); - - str.push_back(c); // Should be faster than str.append(1, c) - } - - return(str.length() ? 256 : -1); -} - diff --git a/waterbox/ss/stream/MemoryStream.h b/waterbox/ss/stream/MemoryStream.h deleted file mode 100644 index 7ffb029006..0000000000 --- a/waterbox/ss/stream/MemoryStream.h +++ /dev/null @@ -1,96 +0,0 @@ -/******************************************************************************/ -/* Mednafen - Multi-system Emulator */ -/******************************************************************************/ -/* MemoryStream.h: -** Copyright (C) 2012-2016 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. -*/ - -/* - Notes: - For performance reasons(like in the state rewinding code), we should try to make sure map() - returns a pointer that is aligned to at least what malloc()/realloc() provides. - (And maybe forcefully align it to at least 16 bytes in the future) -*/ - -#ifndef __MDFN_MEMORYSTREAM_H -#define __MDFN_MEMORYSTREAM_H - -#include "Stream.h" - -class MemoryStream : public Stream -{ - public: - - MemoryStream(); - MemoryStream(uint64 alloc_hint, int alloc_hint_is_size = false); // Pass -1 instead of 1 for alloc_hint_is_size to skip initialization of the memory. - MemoryStream(Stream *stream, uint64 size_limit = ~(uint64)0); - // Will create a MemoryStream equivalent of the contents of "stream", and then "delete stream". - // Will only work if stream->tell() == 0, or if "stream" is seekable. - // stream will be deleted even if this constructor throws. - // - // Will throw an exception if the initial size() of the MemoryStream would be greater than size_limit(useful for when passing - // in GZFileStream streams). - - MemoryStream(const MemoryStream &zs); - MemoryStream & operator=(const MemoryStream &zs); - - virtual ~MemoryStream() override; - - virtual uint64 attributes(void) override; - - virtual uint8 *map(void) noexcept override; - virtual uint64 map_size(void) noexcept override; - virtual void unmap(void) noexcept override; - - virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) override; - virtual void write(const void *data, uint64 count) override; - virtual void truncate(uint64 length) override; - virtual void seek(int64 offset, int whence) override; - virtual uint64 tell(void) override; - virtual uint64 size(void) override; - virtual void flush(void) override; - virtual void close(void) override; - - virtual int get_line(std::string &str) override; - - void shrink_to_fit(void) noexcept; // Minimizes alloced memory. - -#if 0 - // No methods on the object may be called externally(other than the destructor) after steal_malloced_ptr() - INLINE void* steal_malloced_ptr(void) - { - void* ret = data_buffer; - - data_buffer = nullptr; - data_buffer_size = 0; - data_buffer_alloced = 0; - position = 0; - - return ret; - } -#endif - - private: - uint8 *data_buffer; - uint64 data_buffer_size; - uint64 data_buffer_alloced; - - uint64 position; - - void grow_if_necessary(uint64 new_required_size, uint64 hole_end); -}; -#endif diff --git a/waterbox/ss/stream/Stream.cpp b/waterbox/ss/stream/Stream.cpp deleted file mode 100644 index a674dace15..0000000000 --- a/waterbox/ss/stream/Stream.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/******************************************************************************/ -/* Mednafen - Multi-system Emulator */ -/******************************************************************************/ -/* Stream.cpp: -** Copyright (C) 2012-2016 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. -*/ - -#define _GNU_SOURCE -#include -#include "ss.h" -#include "Stream.h" - -#include - -Stream::Stream() -{ - -} - -Stream::~Stream() -{ - -} - -void Stream::require_fast_seekable(void) -{ - const auto attr = attributes(); - - if(!(attr & ATTRIBUTE_SEEKABLE)) - abort();//throw MDFN_Error(0, _("Stream is not seekable.")); - - if(attr & ATTRIBUTE_SLOW_SEEK) - abort();//throw MDFN_Error(0, _("Stream is not capable of fast seeks.")); -} - -uint64 Stream::read_discard(uint64 count) -{ - uint8 buf[1024]; - uint64 tmp; - uint64 ret = 0; - - do - { - tmp = read(buf, std::min(count, sizeof(buf)), false); - count -= tmp; - ret += tmp; - } while(tmp == sizeof(buf)); - - return ret; -} - -uint64 Stream::alloc_and_read(void** data_out, uint64 size_limit) -{ - uint8 *data_buffer = NULL; - uint64 data_buffer_size = 0; - uint64 data_buffer_alloced = 0; - - //try - //{ - if(attributes() & ATTRIBUTE_SLOW_SIZE) - { - uint64 rti; - - data_buffer_size = 0; - data_buffer_alloced = 65536; - - if(!(data_buffer = (uint8*)realloc(data_buffer, data_buffer_alloced))) - abort();//throw MDFN_Error(ErrnoHolder(errno)); - - while((rti = read(data_buffer + data_buffer_size, data_buffer_alloced - data_buffer_size, false)) > 0) - { - uint8* new_data_buffer; - - data_buffer_size += rti; - - if(data_buffer_size == data_buffer_alloced) - { - data_buffer_alloced <<= 1; - - if(data_buffer_alloced >= SIZE_MAX) - abort();//throw MDFN_Error(ErrnoHolder(ENOMEM)); - - if(data_buffer_alloced > size_limit) // So we can test against our size limit without going far far over it in temporary memory allocations. - data_buffer_alloced = size_limit + 1; - - if(data_buffer_size > size_limit) - abort();//throw MDFN_Error(0, _("Size limit of %llu bytes would be exceeded."), (unsigned long long)size_limit); - - if(data_buffer_alloced > SIZE_MAX) - abort();//throw MDFN_Error(ErrnoHolder(ENOMEM)); - - if(!(new_data_buffer = (uint8 *)realloc(data_buffer, data_buffer_alloced))) - abort();//throw MDFN_Error(ErrnoHolder(errno)); - data_buffer = new_data_buffer; - } - else // EOS - break; - } - - if(data_buffer_alloced > data_buffer_size) - { - uint8 *new_data_buffer; - const uint64 new_data_buffer_alloced = std::max(data_buffer_size, 1); - - new_data_buffer = (uint8*)realloc(data_buffer, new_data_buffer_alloced); - - if(new_data_buffer != NULL) - { - data_buffer = new_data_buffer; - data_buffer_alloced = new_data_buffer_alloced; - } - } - } - else - { - data_buffer_size = size(); - data_buffer_size -= std::min(data_buffer_size, tell()); - data_buffer_alloced = std::max(data_buffer_size, 1); - - if(data_buffer_size > size_limit) - abort();//throw MDFN_Error(0, _("Size limit of %llu bytes would be exceeded."), (unsigned long long)size_limit); - - if(data_buffer_alloced > SIZE_MAX) - abort();//throw MDFN_Error(ErrnoHolder(ENOMEM)); - - if(!(data_buffer = (uint8*)realloc(data_buffer, data_buffer_alloced))) - abort();//throw MDFN_Error(ErrnoHolder(errno)); - - read(data_buffer, data_buffer_size); - } - //} - //catch(...) - //{ - // if(data_buffer) - // { - // free(data_buffer); - // data_buffer = NULL; - // } - // throw; - //} - - *data_out = data_buffer; - return data_buffer_size; -} - - -uint8* Stream::map(void) noexcept -{ - return(NULL); -} - -uint64 Stream::map_size(void) noexcept -{ - return 0; -} - -void Stream::unmap(void) noexcept -{ - -} - -void Stream::put_line(const std::string& str) -{ - char l = '\n'; - - write(&str[0], str.size()); - write(&l, sizeof(l)); -} - - -void Stream::print_format(const char *format, ...) -{ - char *str = NULL; - int rc; - - va_list ap; - - va_start(ap, format); - - rc = vasprintf(&str, format, ap); - - va_end(ap); - - if(rc < 0) - abort();//throw MDFN_Error(0, "Error in trio_vasprintf()"); - else - { - write(str, rc); - free(str); - } -} - -int Stream::get_line(std::string &str) -{ - uint8 c; - - str.clear(); // or str.resize(0)?? - - while(read(&c, sizeof(c), false) > 0) - { - if(c == '\r' || c == '\n' || c == 0) - return(c); - - str.push_back(c); - } - - return(str.length() ? 256 : -1); -} - diff --git a/waterbox/ss/stream/Stream.h b/waterbox/ss/stream/Stream.h deleted file mode 100644 index 54c0ee580d..0000000000 --- a/waterbox/ss/stream/Stream.h +++ /dev/null @@ -1,256 +0,0 @@ -/******************************************************************************/ -/* Mednafen - Multi-system Emulator */ -/******************************************************************************/ -/* Stream.h: -** Copyright (C) 2012-2016 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_STREAM_H -#define __MDFN_STREAM_H - -// TODO?: BufferedStream, no virtual functions, yes inline functions, constructor takes a Stream* argument. - -#include - -#include // For SEEK_* defines, which we will use in Stream out of FORCE OF HABIT. -#include - -#include - -/* - The data read into the pointer passed to read*() functions should be considered undefined if the function throws - or propagates an exception. -*/ - -class Stream -{ - public: - - Stream(); - virtual ~Stream(); - - enum - { - ATTRIBUTE_READABLE = 1U << 0, - ATTRIBUTE_WRITEABLE = 1U << 1, - ATTRIBUTE_SEEKABLE = 1U << 2, // Indicates that Stream is capable of being seeked, regardless of how performant seeking is. - - ATTRIBUTE_SLOW_SEEK = 1U << 3, // Indicates that seeking(particularly backwards) is slow, and should be avoided if at all possible. - ATTRIBUTE_SLOW_SIZE = 1U << 4 // Indicates that size() is slow, and should be avoided if at all possible. - }; - virtual uint64 attributes(void) = 0; - - // - // Throw an exception if stream is not fast-seekable; exists to allow for class-specific generic but helpful - // error messages(such as perhaps "MeowZip file is missing a seek index."). - // - virtual void require_fast_seekable(void); - - virtual uint8 *map(void) noexcept; - // Map the entirety of the stream data into the address space of the process, if possible, and return a pointer. - // (the returned pointer must be cached, and returned on any subsequent calls to map() without an unmap() - // in-between, to facilitate a sort of "feature-testing", to determine if an alternative like "MemoryStream" - // should be used). - // - // If the mapping fails for whatever reason, return NULL rather than throwing an exception. - // - // For code using this functionality, ensure usage of map_size() instead of size(), unless you're only using a specific derived - // class like MemoryStream() where the value returned by size() won't change unexpectedly due to outside factors. - - virtual uint64 map_size(void) noexcept; - // The size of the memory mapping area, point to which returned by map(). - // - // Returns 0 on supported, or if no mapping currently exists. - - virtual void unmap(void) noexcept; - // Unmap the stream data from the address space. (Possibly invalidating the pointer returned from map()). - // (must automatically be called, if necessary, from the destructor). - // - // If the data can't be "unmapped" as such because it was never mmap()'d or similar in the first place(such as with MemoryStream), - // then this will be a nop. - - virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) = 0; - virtual void write(const void *data, uint64 count) = 0; - - virtual void truncate(uint64 length) = 0; // Should have ftruncate()-like semantics; but avoid using it to extend files. - - virtual void seek(int64 offset, int whence = SEEK_SET) = 0; - inline void rewind(void) - { - seek(0, SEEK_SET); - } - virtual uint64 tell(void) = 0; - virtual uint64 size(void) = 0; // May implicitly call flush() if the stream is writeable. - virtual void flush(void) = 0; - virtual void close(void) = 0; // Flushes(in the case of writeable streams) and closes the stream. - // Necessary since this operation can fail(running out of disk space, for instance), - // and throw an exception in the destructor would be a Bad Idea(TM). - // - // Manually calling this function isn't strictly necessary, but recommended when the - // stream is writeable; it will be called automatically from the destructor, with any - // exceptions thrown caught and logged. - - // - // Utility functions(TODO): - // - INLINE uint8 get_u8(void) - { - uint8 ret; - - read(&ret, sizeof(ret)); - - return ret; - } - - INLINE void put_u8(uint8 c) - { - write(&c, sizeof(c)); - } - - - template - INLINE T get_NE(void) - { - T ret; - - read(&ret, sizeof(ret)); - - return ret; - } - - - template - INLINE T get_RE(void) - { - uint8 tmp[sizeof(T)]; - union - { - T ret; - uint8 ret_u8[sizeof(T)]; - }; - - read(tmp, sizeof(tmp)); - - for(unsigned i = 0; i < sizeof(T); i++) - ret_u8[i] = tmp[sizeof(T) - 1 - i]; - - return ret; - } - - template - INLINE void put_NE(T c) - { - write(&c, sizeof(c)); - } - - template - INLINE void put_RE(T c) - { - uint8 tmp[sizeof(T)]; - - for(unsigned i = 0; i < sizeof(T); i++) - tmp[i] = ((uint8 *)&c)[sizeof(T) - 1 - i]; - - write(tmp, sizeof(tmp)); - } - - template - INLINE T get_LE(void) - { - #ifdef LSB_FIRST - return get_NE(); - #else - return get_RE(); - #endif - } - - template - INLINE void put_LE(T c) - { - #ifdef LSB_FIRST - return put_NE(c); - #else - return put_RE(c); - #endif - } - - template - INLINE T get_BE(void) - { - #ifndef LSB_FIRST - return get_NE(); - #else - return get_RE(); - #endif - } - - template - INLINE void put_BE(T c) - { - #ifndef LSB_FIRST - return put_NE(c); - #else - return put_RE(c); - #endif - } - - INLINE void put_string(const char* str) - { - write(str, strlen(str)); - } - - // Reads a line into "str", overwriting its contents; returns the line-end char('\n' or '\r' or '\0'), or 256 on EOF and - // data has been read into "str", and -1 on EOF when no data has been read into "str". - // The line-end char won't be added to "str". - // It's up to the caller to handle extraneous empty lines caused by DOS-format text lines(\r\n). - // ("str" is passed by reference for the possibility of improved performance by reusing alloced memory for the std::string, though part - // of it would be up to the STL implementation). - // Implemented as virtual so that a higher-performance version can be implemented if possible(IE with MemoryStream) - virtual int get_line(std::string &str); - - virtual void put_line(const std::string& str); - - virtual void print_format(const char *format, ...) MDFN_FORMATSTR(gnu_printf, 2, 3); - -#if 0 - int scanf(const char *format, ...) MDFN_FORMATSTR(gnu_scanf, 2, 3); - void put_string(const char *str); - void put_string(const std::string &str); -#endif - - // - // Read until end-of-stream(or count), discarding any read data, and returns the amount of data "read". - // (Useful for detecting and printing warnings about extra garbage data without needing to call size(), - // which can be problematic for some types of Streams). - uint64 read_discard(uint64 count = ~(uint64)0); - - // - // Reads stream starting at the current stream position(as returned by tell()), into memory allocated with malloc() and realloc(), and - // sets *data_out to a pointer to the memory(which the caller will need to free() at some point). - // - // *data_out is only an output. - // - // If size_limit is/will be exceeded, an exception will be thrown, and *data_out will not be written to. - // - // Will return the amount of data read. - // - // If the returned value is 0, *data_out will still be a valid non-NULL pointer. - // - uint64 alloc_and_read(void** data_out, uint64 size_limit = ~(uint64)0); -}; - -#endif