psx: multitap support. tested for 20 seconds, but worth someone else testing.

This commit is contained in:
zeromus 2017-04-29 04:11:09 -05:00
parent 27e419bba5
commit d3a1ec64dd
6 changed files with 120 additions and 53 deletions

View File

@ -409,9 +409,26 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
SetControllerButtons(); SetControllerButtons();
var fioCfg = _SyncSettings.FIOConfig; var fioCfg = _SyncSettings.FIOConfig;
if(fioCfg.Devices8[0] != OctoshockDll.ePeripheralType.None) if (fioCfg.Multitaps[0])
{
OctoshockDll.shock_Peripheral_Connect(psx, 0x01, OctoshockDll.ePeripheralType.Multitap);
OctoshockDll.shock_Peripheral_Connect(psx, 0x11, fioCfg.Devices8[0]);
OctoshockDll.shock_Peripheral_Connect(psx, 0x21, fioCfg.Devices8[1]);
OctoshockDll.shock_Peripheral_Connect(psx, 0x31, fioCfg.Devices8[2]);
OctoshockDll.shock_Peripheral_Connect(psx, 0x41, fioCfg.Devices8[3]);
}
else
OctoshockDll.shock_Peripheral_Connect(psx, 0x01, fioCfg.Devices8[0]); OctoshockDll.shock_Peripheral_Connect(psx, 0x01, fioCfg.Devices8[0]);
if (fioCfg.Devices8[4] != OctoshockDll.ePeripheralType.None)
if (fioCfg.Multitaps[1])
{
OctoshockDll.shock_Peripheral_Connect(psx, 0x02, OctoshockDll.ePeripheralType.Multitap);
OctoshockDll.shock_Peripheral_Connect(psx, 0x12, fioCfg.Devices8[4]);
OctoshockDll.shock_Peripheral_Connect(psx, 0x22, fioCfg.Devices8[5]);
OctoshockDll.shock_Peripheral_Connect(psx, 0x32, fioCfg.Devices8[6]);
OctoshockDll.shock_Peripheral_Connect(psx, 0x42, fioCfg.Devices8[7]);
}
else
OctoshockDll.shock_Peripheral_Connect(psx, 0x02, fioCfg.Devices8[4]); OctoshockDll.shock_Peripheral_Connect(psx, 0x02, fioCfg.Devices8[4]);
var memcardTransaction = new OctoshockDll.ShockMemcardTransaction() var memcardTransaction = new OctoshockDll.ShockMemcardTransaction()
@ -456,9 +473,11 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
{ {
var fioCfg = _SyncSettings.FIOConfig.ToLogical(); var fioCfg = _SyncSettings.FIOConfig.ToLogical();
int portNum = 0x01; for(int port=0;port<2;port++)
foreach (int slot in new[] { 0, 4 }) for(int multiport=0;multiport<4;multiport++)
{ {
int portNum = (port+1) + ((multiport+1) << 4);
int slot = port * 4 + multiport;
//no input to set //no input to set
if (fioCfg.Devices8[slot] == OctoshockDll.ePeripheralType.None) if (fioCfg.Devices8[slot] == OctoshockDll.ePeripheralType.None)
continue; continue;
@ -518,8 +537,6 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
OctoshockDll.shock_Peripheral_SetPadInput(psx, portNum, buttons, left_x, left_y, right_x, right_y); OctoshockDll.shock_Peripheral_SetPadInput(psx, portNum, buttons, left_x, left_y, right_x, right_y);
} }
portNum <<= 1;
} }
} }

Binary file not shown.

View File

@ -135,6 +135,8 @@ FrontIO::FrontIO()
Ports[i] = new InputDevice(); Ports[i] = new InputDevice();
PortData[i] = NULL; PortData[i] = NULL;
MCPorts[i] = new InputDevice(); MCPorts[i] = new InputDevice();
emulate_multitap[i] = false;
DevicesTap[i] = new InputDevice_Multitap();
} }
} }
@ -145,6 +147,7 @@ FrontIO::~FrontIO()
{ {
delete Ports[i]; delete Ports[i];
delete MCPorts[i]; delete MCPorts[i];
delete DevicesTap[i];
} }
delete DummyDevice; delete DummyDevice;
} }
@ -573,16 +576,8 @@ void FrontIO::Reset(bool powering_up)
istatus = false; istatus = false;
} }
void FrontIO::UpdateInput(void)
{
for(int i=0;i<2;i++)
{
if(Ports[i] != NULL) Ports[i]->UpdateInput(PortData[i]);
}
}
// Take care to call ->Power() only if the device actually changed. // Take care to call ->Power() only if the device actually changed.
void FrontIO::SetInput(unsigned int port, const char *type, void *ptr) void FrontIO::SetInput(unsigned int port, unsigned int multiport, const char *type, void *ptr)
{ {
//clean up the old device //clean up the old device
delete Ports[port]; delete Ports[port];
@ -604,6 +599,8 @@ void FrontIO::SetInput(unsigned int port, const char *type, void *ptr)
Ports[port] = Device_GunCon_Create(); Ports[port] = Device_GunCon_Create();
else if(!strcmp(type, "justifier")) else if(!strcmp(type, "justifier"))
Ports[port] = Device_Justifier_Create(); Ports[port] = Device_Justifier_Create();
else if (!strcmp(type, "multitap"))
Ports[port] = new InputDevice_Multitap();
else else
Ports[port] = new InputDevice(); Ports[port] = new InputDevice();

View File

@ -77,7 +77,7 @@ class FrontIO
void GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider); void GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider);
void UpdateInput(void); void UpdateInput(void);
void SetInput(unsigned int port, const char *type, void *ptr); void SetInput(unsigned int port, unsigned int multiport, const char *type, void *ptr);
void SetCrosshairsColor(unsigned port, uint32 color); void SetCrosshairsColor(unsigned port, uint32 color);
uint64 GetMemcardDirtyCount(unsigned int which); uint64 GetMemcardDirtyCount(unsigned int which);
@ -88,7 +88,7 @@ class FrontIO
InputDevice *MCPorts[2]; InputDevice *MCPorts[2];
InputDevice *DummyDevice; InputDevice *DummyDevice;
private: //private:
void DoDSRIRQ(void); void DoDSRIRQ(void);
void CheckStartStopPending(pscpu_timestamp_t timestamp, bool skip_event_set = false); void CheckStartStopPending(pscpu_timestamp_t timestamp, bool skip_event_set = false);
@ -99,8 +99,8 @@ class FrontIO
//OLD //OLD
//bool emulate_memcards[8]; //bool emulate_memcards[8];
//void MapDevicesToPorts(void); //void MapDevicesToPorts(void);
//bool emulate_multitap[2]; bool emulate_multitap[2];
//InputDevice_Multitap *DevicesTap[2]; InputDevice_Multitap *DevicesTap[2];
//InputDevice *Devices[8]; //InputDevice *Devices[8];
//void *DeviceData[8]; //void *DeviceData[8];
//InputDevice *DevicesMC[8]; //InputDevice *DevicesMC[8];

View File

@ -97,14 +97,22 @@ InputDevice_Multitap::InputDevice_Multitap()
{ {
for(int i = 0; i < 4; i++) for(int i = 0; i < 4; i++)
{ {
pad_devices[i] = NULL; //dummies
mc_devices[i] = NULL; pad_devices[i] = new InputDevice();
mc_devices[i] = new InputDevice();
} }
Power(); Power();
} }
InputDevice_Multitap::~InputDevice_Multitap() InputDevice_Multitap::~InputDevice_Multitap()
{ {
for (int i = 0; i < 4; i++)
{
delete pad_devices[i];
delete mc_devices[i];
pad_devices[i] = NULL;
mc_devices[i] = NULL;
}
} }
void InputDevice_Multitap::SetSubDevice(unsigned int sub_index, InputDevice *device, InputDevice *mc_device) void InputDevice_Multitap::SetSubDevice(unsigned int sub_index, InputDevice *device, InputDevice *mc_device)
@ -113,6 +121,9 @@ void InputDevice_Multitap::SetSubDevice(unsigned int sub_index, InputDevice *dev
//printf("%d\n", sub_index); //printf("%d\n", sub_index);
delete pad_devices[sub_index];
delete mc_devices[sub_index];
pad_devices[sub_index] = device; pad_devices[sub_index] = device;
mc_devices[sub_index] = mc_device; mc_devices[sub_index] = mc_device;
} }

View File

@ -34,6 +34,7 @@
#include "input/negcon.h" #include "input/negcon.h"
#include "input/gamepad.h" #include "input/gamepad.h"
#include "input/memcard.h" #include "input/memcard.h"
#include "input/multitap.h"
#include <stdarg.h> #include <stdarg.h>
@ -1050,13 +1051,34 @@ struct ShockPeripheral
{ {
ePeripheralType type; ePeripheralType type;
u8 buffer[32]; //must be larger than 16+3+1 or thereabouts because the dualshock writes some rumble data into it. bleck, ill fix it later u8 buffer[32]; //must be larger than 16+3+1 or thereabouts because the dualshock writes some rumble data into it. bleck, ill fix it later
//TODO: test for multitap. does it need to be as large as 4 of whatever the single largest port would be?
//well, it must manage its own stuff.. its not like we feed in external data, right?
InputDevice* device;
}; };
static int addressToPortNum(int address)
{
int portnum = SHOCK_INVALID_ADDRESS;
//WHY did I choose 1 indexed? I dunno, let's roll with it
if (address == 0x01) portnum = 0;
else if (address == 0x02) portnum = 1;
else if (address == 0x11) portnum = 2;
else if (address == 0x21) portnum = 3;
else if (address == 0x31) portnum = 4;
else if (address == 0x41) portnum = 5;
else if (address == 0x12) portnum = 6;
else if (address == 0x22) portnum = 7;
else if (address == 0x32) portnum = 8;
else if (address == 0x42) portnum = 9;
return portnum;
}
struct { struct {
//This is kind of redundant with the frontIO code, and should be merged with it eventually, when the configurability gets more advanced //"This is kind of redundant with the frontIO code, and should be merged with it eventually, when the configurability gets more advanced"
//I dunno.
ShockPeripheral ports[2]; ShockPeripheral ports[10];
void Initialize() void Initialize()
{ {
@ -1067,13 +1089,12 @@ struct {
} }
} }
//TODO: "Take care to call ->Power() only if the device actually changed."
//(like, is this about savestates? seems silly"
s32 Connect(s32 address, s32 type) s32 Connect(s32 address, s32 type)
{ {
//check the port address int portnum = addressToPortNum(address);
int portnum = address&0x0F; if(portnum == SHOCK_INVALID_ADDRESS) return SHOCK_INVALID_ADDRESS;
if(portnum != 1 && portnum != 2)
return SHOCK_INVALID_ADDRESS;
portnum--;
//check whats already there //check whats already there
if(ports[portnum].type == ePeripheralType_None && type == ePeripheralType_None) return SHOCK_OK; //NOP if(ports[portnum].type == ePeripheralType_None && type == ePeripheralType_None) return SHOCK_OK; //NOP
@ -1083,35 +1104,50 @@ struct {
if(type == ePeripheralType_None) { if(type == ePeripheralType_None) {
ports[portnum].type = ePeripheralType_None; ports[portnum].type = ePeripheralType_None;
memset(ports[portnum].buffer,0,sizeof(ports[portnum].buffer)); memset(ports[portnum].buffer,0,sizeof(ports[portnum].buffer));
FIO->SetInput(portnum, "none", ports[portnum].buffer);
return SHOCK_OK; //fall through to setup a nonexistent `next` for disconnecting, instead of returning now
} }
//connecting: //connecting:
const char* name = NULL; InputDevice* next = nullptr;
switch(type) switch(type)
{ {
case ePeripheralType_Pad: name = "gamepad"; break; case ePeripheralType_Pad: next = Device_Gamepad_Create(); break;
case ePeripheralType_DualShock: name = "dualshock"; break; case ePeripheralType_DualShock: next = Device_DualShock_Create(); break;
case ePeripheralType_DualAnalog: name = "dualanalog"; break; case ePeripheralType_DualAnalog: next = Device_DualAnalog_Create(false); break;
case ePeripheralType_NegCon: name = "negcon"; break; case ePeripheralType_Multitap: next = new InputDevice_Multitap(); break;
case ePeripheralType_NegCon: next = Device_neGcon_Create(); break;
case ePeripheralType_None: next = new InputDevice(); break; //dummy
break;
default: default:
return SHOCK_ERROR; return SHOCK_ERROR;
} }
ports[portnum].type = (ePeripheralType)type; ports[portnum].type = (ePeripheralType)type;
ports[portnum].device = next;
memset(ports[portnum].buffer,0,sizeof(ports[portnum].buffer)); memset(ports[portnum].buffer,0,sizeof(ports[portnum].buffer));
FIO->SetInput(portnum, name, ports[portnum].buffer);
if (portnum == 0 || portnum == 1)
{
FIO->Ports[portnum] = next;
FIO->PortData[portnum] = ports[portnum].buffer;
}
else {
//must be multitap child device
int portidx = (address & 0xF) - 1;
int subidx = (address >> 4) - 1;
auto tap = (InputDevice_Multitap*)FIO->Ports[portidx];
auto mcdummy = new InputDevice();
//next->
tap->SetSubDevice(subidx, next, mcdummy);
}
return SHOCK_OK; return SHOCK_OK;
} }
s32 PollActive(s32 address, bool clear) s32 PollActive(s32 address, bool clear)
{ {
//check the port address int portnum = addressToPortNum(address);
int portnum = address&0x0F; if (portnum == SHOCK_INVALID_ADDRESS) return SHOCK_INVALID_ADDRESS;
if(portnum != 1 && portnum != 2)
return SHOCK_INVALID_ADDRESS;
portnum--;
s32 ret = SHOCK_FALSE; s32 ret = SHOCK_FALSE;
@ -1161,11 +1197,8 @@ struct {
s32 SetPadInput(s32 address, u32 buttons, u8 left_x, u8 left_y, u8 right_x, u8 right_y) s32 SetPadInput(s32 address, u32 buttons, u8 left_x, u8 left_y, u8 right_x, u8 right_y)
{ {
//check the port address int portnum = addressToPortNum(address);
int portnum = address&0x0F; if (portnum == SHOCK_INVALID_ADDRESS) return SHOCK_INVALID_ADDRESS;
if(portnum != 1 && portnum != 2)
return SHOCK_INVALID_ADDRESS;
portnum--;
u8* buf = ports[portnum].buffer; u8* buf = ports[portnum].buffer;
switch(ports[portnum].type) switch(ports[portnum].type)
@ -1219,11 +1252,8 @@ struct {
s32 MemcardTransact(s32 address, ShockMemcardTransaction* transaction) s32 MemcardTransact(s32 address, ShockMemcardTransaction* transaction)
{ {
//check the port address int portnum = addressToPortNum(address);
int portnum = address&1; if (portnum == SHOCK_INVALID_ADDRESS) return SHOCK_INVALID_ADDRESS;
if(portnum != 1 && portnum != 2)
return SHOCK_INVALID_ADDRESS;
portnum--;
//TODO - once we get flexible here, do some extra condition checks.. whether memcards exist, etc. much like devices. //TODO - once we get flexible here, do some extra condition checks.. whether memcards exist, etc. much like devices.
switch(transaction->transaction) switch(transaction->transaction)
@ -1261,6 +1291,18 @@ struct {
} }
} }
void UpdateInput()
{
for(int i=0;i<10;i++)
{
for(int i=0;i<ARRAY_SIZE(ports);i++)
{
if(ports[i].device)
ports[i].device->UpdateInput(ports[i].buffer);
}
}
}
} s_ShockPeripheralState; } s_ShockPeripheralState;
EW_EXPORT s32 shock_Peripheral_Connect(void* psx, s32 address, s32 type) EW_EXPORT s32 shock_Peripheral_Connect(void* psx, s32 address, s32 type)
@ -1367,7 +1409,7 @@ EW_EXPORT s32 shock_PowerOn(void* psx)
{ {
if(s_ShockState.power) return SHOCK_NOCANDO; if(s_ShockState.power) return SHOCK_NOCANDO;
s_ShockState.power = true; s_ShockState.power = true;
PSX_Power(true); PSX_Power(true);
return SHOCK_OK; return SHOCK_OK;
@ -1427,7 +1469,7 @@ EW_EXPORT s32 shock_Step(void* psx, eShockStep step)
//------------------------- //-------------------------
FIO->UpdateInput(); s_ShockPeripheralState.UpdateInput();
//GPU->StartFrame(psf_loader ? NULL : espec); //a reminder that when we do psf, we will be telling the gpu not to draw //GPU->StartFrame(psf_loader ? NULL : espec); //a reminder that when we do psf, we will be telling the gpu not to draw
GPU->StartFrame(&espec); GPU->StartFrame(&espec);