Star Wars Trilogy lever feedback activated

This commit is contained in:
SpinDizzy 2020-10-24 09:12:54 +00:00
parent 402baf87b8
commit 5143669cb9
4 changed files with 318 additions and 53 deletions

View file

@ -2086,8 +2086,8 @@
<patches>
<!-- skip force feedback lever check -->
<!-- <patch region="crom" bits="32" offset="0xf6e44" value="0x60000000" /> --> <!-- from MAME -->
<patch region="crom" bits="32" offset="0xf0e48" value="0x60000000" />
<patch region="crom" bits="32" offset="0x043dc" value="0x48000090" /> <!-- related to joystick feedback -->
<!--<patch region="crom" bits="32" offset="0xf0e48" value="0x60000000" /> --> <!-- no more needed if ffb lever rom loaded -->
<!--<patch region="crom" bits="32" offset="0x043dc" value="0x48000090" /> --> <!-- related to joystick feedback --> <!-- no more needed if ffb lever rom loaded -->
<patch region="crom" bits="32" offset="0x029a0" value="0x60000000" /> <!-- skip force feedback setup? -->
<patch region="crom" bits="32" offset="0x02a0c" value="0x60000000" />
<!-- Additional patches from MAME for test menu -->
@ -2153,11 +2153,11 @@
<file offset="0xC00000" name="mpr-21378.24" crc32="0x1FCF715E" />
</region>
<!-- Force feedback controller prg -->
<!--
<region name="ffb_program" stride="1" chunk_size="1">
<file offset="0" name="epr-21119.ic8" crc32="0x65082B14" />
</region>
-->
</roms>
</game>
@ -2184,10 +2184,14 @@
<!--<patch region="crom" bits="32" offset="0xf6dd0" value="0x60000000" /> --> <!-- from MAME -->
<!-- Spindizzi notes : mimic patch from Bart's patch in swtrilgy to prevent game to be slow-->
<!-- instead of patch we can make hack timing in code -->
<patch region="crom" bits="32" offset="0x043dc" value="0x48000090" />
<!--<patch region="crom" bits="32" offset="0x043dc" value="0x48000090" />--> <!-- no more needed if ffb lever rom loaded -->
<patch region="crom" bits="32" offset="0x029a0" value="0x60000000" />
<patch region="crom" bits="32" offset="0x02a0c" value="0x60000000" />
<patch region="crom" bits="32" offset="0xf0dd4" value="0x60000000" />
<!--<patch region="crom" bits="32" offset="0xf0dd4" value="0x60000000" />--> <!-- no more needed if ffb lever rom loaded -->
<!-- Additional patches from MAME for test menu -->
<patch region="crom" bits="32" offset="0xf76f8" value="0x60000000" /> <!-- unemulated JTAG stuff -->
<patch region="crom" bits="32" offset="0xf76fc" value="0x60000000" /> <!-- "" -->
<patch region="crom" bits="32" offset="0xf7700" value="0x60000000" /> <!-- "" -->
</patches>
<region name="crom" stride="8" chunk_size="2" byte_swap="true">
<file offset="0" name="epr-21382.20" crc32="0x0B9C44A0" />

View file

@ -254,8 +254,10 @@ void CDriveBoard::Reset(void)
m_adcPortRead = 0;
m_adcPortBit = 0;
m_port42Out = 0;
m_port45Out = 0;
m_port46Out = 0;
m_prev42Out = 0;
m_prev45Out = 0;
m_prev46Out = 0;
m_initState = 0;
@ -266,6 +268,7 @@ void CDriveBoard::Reset(void)
m_uncenterVal2 = 0;
m_lastConstForce = 0;
m_lastConstForceY = 0;
m_lastSelfCenter = 0;
m_lastFriction = 0;
m_lastVibrate = 0;
@ -496,32 +499,29 @@ UINT8 CDriveBoard::IORead8(UINT32 portNum)
UINT8 adcVal;
switch (portNum)
{
case 32: // DIP 1 value
case 0x20: // DIP 1 value
return m_dip1;
case 33: // DIP 2 value
case 0x21: // DIP 2 value
return m_dip2;
case 36: // ADC channel 1 - not connected
case 37: // ADC channel 2 - steering wheel position (0x00 = full left, 0x80 = center, 0xFF = full right)
case 38: // ADC channel 3 - cockpit bank position (deluxe cabinets) (0x00 = full left, 0x80 = center, 0xFF = full right)
case 39: // ADC channel 4 - not connected
case 0x24: // ADC channel 1 - Y analog axis for joystick
case 0x25: // ADC channel 2 - steering wheel position (0x00 = full left, 0x80 = center, 0xFF = full right) and X analog axis for joystick
case 0x26: // ADC channel 3 - cockpit bank position (deluxe cabinets) (0x00 = full left, 0x80 = center, 0xFF = full right)
case 0x27: // ADC channel 4 - not connected
if (portNum == m_adcPortRead && m_adcPortBit-- > 0)
{
switch (portNum)
{
case 36: // Not connected
adcVal = 0x00;
case 0x24: // Y analog axis for joystick
adcVal = ReadADCChannel1();
break;
case 37: // Steering wheel for twin racing cabinets - TODO - check actual range of steering, suspect it is not really 0x00-0xFF
if (m_initialized)
adcVal = (UINT8)m_inputs->steering->value;
else
adcVal = 0x80; // If not initialized, return 0x80 so that wheel centering test does not fail
case 0x25: // Steering wheel for twin racing cabinets - TODO - check actual range of steering, suspect it is not really 0x00-0xFF
adcVal = ReadADCChannel2();
break;
case 38: // Cockpit bank position for deluxe racing cabinets
adcVal = 0x80;
case 0x26: // Cockpit bank position for deluxe racing cabinets
adcVal = ReadADCChannel3();
break;
case 39: // Not connected
adcVal = 0x00;
case 0x27: // Not connected
adcVal = ReadADCChannel4();
break;
default:
#ifdef DEBUG
@ -538,9 +538,9 @@ UINT8 CDriveBoard::IORead8(UINT32 portNum)
#endif
return 0xFF;
}
case 40: // PPC command
case 0x28: // PPC command
return m_dataSent;
case 44: // Encoder error reporting (kept at 0x00 for no error)
case 0x2c: // Encoder error reporting (kept at 0x00 for no error)
// Bit 1 0
// 0 0 = encoder okay, no error
// 0 1 = encoder error 1 - overcurrent error
@ -559,55 +559,66 @@ void CDriveBoard::IOWrite8(UINT32 portNum, UINT8 data)
{
switch (portNum)
{
case 16: // Unsure? - single byte 0x03 sent at initialization, then occasionally writes 0x07 & 0xFA to port
case 0x10: // Unsure? - single byte 0x03 sent at initialization, then occasionally writes 0x07 & 0xFA to port
return;
case 17: // Interrupt control
case 0x11: // Interrupt control
if (data == 0x57)
m_allowInterrupts = true;
else if (data == 0x53) // Strictly speaking 0x53 then 0x04
m_allowInterrupts = false;
return;
case 28: // Unsure? - two bytes 0xFF, 0xFF sent at initialization only
case 29: // Unsure? - two bytes 0x0F, 0x17 sent at initialization only
case 30: // Unsure? - same as port 28
case 31: // Unsure? - same as port 31
case 0x1c: // Unsure? - two bytes 0xFF, 0xFF sent at initialization only
case 0x1d: // Unsure? - two bytes 0x0F, 0x17 sent at initialization only
case 0x1e: // Unsure? - same as port 28
case 0x1f: // Unsure? - same as port 31
return;
case 32: // Left digit of 7-segment display 1
case 0x20: // Left digit of 7-segment display 1
m_seg1Digit1 = data;
return;
case 33: // Right digit of 7-segment display 1
case 0x21: // Right digit of 7-segment display 1
m_seg1Digit2 = data;
return;
case 34: // Left digit of 7-segment display 2
case 0x22: // Left digit of 7-segment display 2
m_seg2Digit1 = data;
return;
case 35: // Right digit of 7-segment display 2
case 0x23: // Right digit of 7-segment display 2
m_seg2Digit2 = data;
return;
case 36: // ADC channel 1 control
case 37: // ADC channel 2 control
case 38: // ADC channel 3 control
case 39: // ADC channel 4 control
case 0x24: // ADC channel 1 control
case 0x25: // ADC channel 2 control
case 0x26: // ADC channel 3 control
case 0x27: // ADC channel 4 control
m_adcPortRead = portNum;
m_adcPortBit = 8;
return;
case 41: // Reply for PPC
case 0x29: // Reply for PPC
m_dataReceived = data;
if (data == 0xCC)
if ((data == 0xCC && m_boardType == Wheel) || (data==0xCB && m_boardType == Joystick))
m_initialized = true;
return;
case 42: // Encoder motor data
case 0x2a: // Encoder motor data (x axis)
m_port42Out = data;
ProcessEncoderCmd();
switch (m_boardType)
{
case Wheel:
ProcessEncoderCmd();
break;
case Joystick:
ProcessEncoderCmdJoystick();
break;
}
return;
case 45: // Clutch/lamp control (deluxe cabinets)
case 0x2d: // Clutch/lamp control (deluxe cabinets) ( or y axis)
m_port45Out = data;
if (m_boardType==Joystick)
ProcessEncoderCmdJoystick();
return;
case 46: // Encoder motor control
case 0x2e: // Encoder motor control
m_port46Out = data;
return;
case 240: // Unsure? - single byte 0xBB sent at initialization only
case 0xf0: // Unsure? - single byte 0xBB sent at initialization only
return;
case 241: // Unsure? - single byte 0x4E sent regularly - some sort of watchdog?
case 0xf1: // Unsure? - single byte 0x4E sent regularly - some sort of watchdog?
return;
default:
#ifdef DEBUG
@ -719,18 +730,148 @@ void CDriveBoard::ProcessEncoderCmd(void)
}
}
void CDriveBoard::ProcessEncoderCmdJoystick(void)
{
if (m_prev42Out != m_port42Out || m_prev46Out != m_port46Out || m_prev45Out != m_port45Out)
{
switch (m_port46Out)
{
case 0xEE:
// Apply constant force
if (m_port42Out > 0x7f) // X
{
SendConstantForce(2 * (m_port42Out - 0x7f));
}
else if (m_port42Out < 0x7f)
{
SendConstantForce(2 * (m_port42Out - 0x7f));
}
else
{
SendConstantForce(0);
}
if (m_port45Out > 0x7f) // Y
{
SendConstantForceY(-2 * (m_port45Out - 0x7f));
}
else if (m_port45Out < 0x7f)
{
SendConstantForceY(-2 * (m_port45Out - 0x7f));
}
else
{
SendConstantForceY(0);
}
if (m_port42Out == 0x7f && m_port45Out == 0x81)
{
SendSelfCenter(255);
}
else SendSelfCenter(0);
break;
case 0xFF:
// Stop all effects
if (m_port42Out == 0 || m_port45Out == 0)
SendStopAll();
break;
case 0xcc: // init
//42[0B] / 45[0A]
//42[0B] / 45[0B]
//42[FF] / 45[0B]
//42[FF] / 45[FF]
break;
case 0xdd: // init
// 42[FF] / 45[00]
// 42[FF] / 45[FF]
// 42[0A] / 45[00]
// 42[0A] / 45[0A]
break;
case 0xce:
// 42[7F] / 45[08]
// 42[7F] / 45[09]
// 42[7F] / 45[0A]
// 42[7F] / 45[0B]
// 42[7F] / 45[81]
if (m_port42Out == 0x7f && m_port45Out != 0x81) // X
{
SendConstantForce(2 * m_port45Out);
}
if (m_port42Out == 0x7f && m_port45Out == 0x81)
{
SendSelfCenter(255);
}
break;
case 0xec:
// 42[09] / 45[81]
// 42[2A] / 45[81]
// 42[1B] / 45[81]
// 42[7F] / 45[81]
if (m_port45Out == 0x81 && m_port42Out != 0x7f) // Y
{
SendConstantForceY(2 * m_port42Out);
}
if (m_port42Out == 0x7f && m_port45Out == 0x81)
{
SendSelfCenter(255);
}
break;
case 0x00: // init
// 42[FF] / 45[00]
// 42[FF] / 45[FF]
break;
case 0x99: // init
// 42[B0] / 45[B0]
// 42[80] / 45[B0]
// 42[80] / 45[80]
break;
default:
//printf("Unknown = 46 [%02X] / 42 [%02X] / 45 [%02X]\n", m_port46Out, m_port42Out, m_port45Out);
break;
}
m_prev42Out = m_port42Out;
m_prev46Out = m_port46Out;
m_prev45Out = m_port45Out;
}
}
void CDriveBoard::SendStopAll(void)
{
//printf(">> Stop All Effects\n");
ForceFeedbackCmd ffCmd;
ffCmd.id = FFStop;
m_inputs->steering->SendForceFeedbackCmd(ffCmd);
switch (m_boardType)
{
case Wheel:
m_inputs->steering->SendForceFeedbackCmd(ffCmd);
break;
case Joystick:
m_inputs->analogJoyX->SendForceFeedbackCmd(ffCmd);
m_inputs->analogJoyY->SendForceFeedbackCmd(ffCmd);
break;
}
m_lastConstForce = 0;
m_lastSelfCenter = 0;
m_lastFriction = 0;
m_lastVibrate = 0;
m_lastConstForceY = 0;
}
void CDriveBoard::SendConstantForce(INT8 val)
@ -759,11 +900,32 @@ void CDriveBoard::SendConstantForce(INT8 val)
ForceFeedbackCmd ffCmd;
ffCmd.id = FFConstantForce;
ffCmd.force = (float)val / (val >= 0 ? 127.0f : 128.0f);
m_inputs->steering->SendForceFeedbackCmd(ffCmd);
switch (m_boardType)
{
case Wheel:
m_inputs->steering->SendForceFeedbackCmd(ffCmd);
break;
case Joystick:
m_inputs->analogJoyX->SendForceFeedbackCmd(ffCmd);
break;
}
m_lastConstForce = val;
}
void CDriveBoard::SendConstantForceY(INT8 val)
{
if (val == m_lastConstForceY)
return;
ForceFeedbackCmd ffCmd;
ffCmd.id = FFConstantForce;
ffCmd.force = (float)val / (val >= 0 ? 127.0f : 128.0f);
m_inputs->analogJoyY->SendForceFeedbackCmd(ffCmd);
m_lastConstForceY = val;
}
void CDriveBoard::SendSelfCenter(UINT8 val)
{
if (val == m_lastSelfCenter)
@ -778,11 +940,22 @@ void CDriveBoard::SendSelfCenter(UINT8 val)
ForceFeedbackCmd ffCmd;
ffCmd.id = FFSelfCenter;
ffCmd.force = (float)val / 255.0f;
m_inputs->steering->SendForceFeedbackCmd(ffCmd);
switch (m_boardType)
{
case Wheel:
m_inputs->steering->SendForceFeedbackCmd(ffCmd);
break;
case Joystick:
m_inputs->analogJoyX->SendForceFeedbackCmd(ffCmd);
m_inputs->analogJoyY->SendForceFeedbackCmd(ffCmd);
break;
}
m_lastSelfCenter = val;
}
void CDriveBoard::SendFriction(UINT8 val)
{
if (val == m_lastFriction)
@ -821,6 +994,59 @@ void CDriveBoard::SendVibrate(UINT8 val)
m_lastVibrate = val;
}
uint8_t CDriveBoard::ReadADCChannel1()
{
switch (m_boardType)
{
case Wheel:
return 0x00;
break;
case Joystick:
if (m_initialized)
return (UINT8)m_inputs->analogJoyY->value;
else
return 0x80; // If not initialized, return 0x80 so that ffb centering test does not fail
break;
}
}
uint8_t CDriveBoard::ReadADCChannel2()
{
switch (m_boardType)
{
case Wheel:
if (m_initialized)
return (UINT8)m_inputs->steering->value;
else
return 0x80; // If not initialized, return 0x80 so that wheel centering test does not fail
break;
case Joystick:
if (m_initialized)
return (UINT8)m_inputs->analogJoyX->value;
else
return 0x80; // If not initialized, return 0x80 so that ffb centering test does not fail
break;
}
}
uint8_t CDriveBoard::ReadADCChannel3()
{
return 0x80;
}
uint8_t CDriveBoard::ReadADCChannel4()
{
switch (m_boardType)
{
case Wheel:
return 0x00;
break;
case Joystick:
return 0x80;
break;
}
}
CDriveBoard::CDriveBoard(const Util::Config::Node &config)
: m_config(config),
m_attached(false),

View file

@ -36,6 +36,14 @@
class CDriveBoard : public IBus
{
public:
enum BoardType
{
Wheel=0,
Joystick
};
BoardType m_boardType;
/*
* IsAttached(void):
*
@ -244,7 +252,7 @@ public:
*/
void Write8(UINT32 addr, UINT8 data);
void IOWrite8(UINT32 portNum, UINT8 data);
private:
const Util::Config::Node &m_config;
bool m_attached; // True if drive board is attached
@ -281,9 +289,11 @@ private:
UINT8 m_port42Out; // Last value sent to Z80 I/O port 42 (encoder motor data)
UINT8 m_port46Out; // Last value sent to Z80 I/O port 46 (encoder motor control)
UINT8 m_port45Out; // Last value sent to Z80 I/O port 42 (up-down motor data)
UINT8 m_prev42Out; // Previous value sent to Z80 I/O port 42
UINT8 m_prev46Out; // Previous value sent to Z80 I/O port 46
UINT8 m_prev45Out; // Previous value sent to Z80 I/O port 45 (up-down)
UINT8 m_uncenterVal1; // First part of pending uncenter command
UINT8 m_uncenterVal2; // Second part of pending uncenter command
@ -299,6 +309,7 @@ private:
// Feedback state
INT8 m_lastConstForce; // Last constant force command sent
INT8 m_lastConstForceY; // Last constant force command sent y axis
UINT8 m_lastSelfCenter; // Last self center command sent
UINT8 m_lastFriction; // Last friction command sent
UINT8 m_lastVibrate; // Last vibrate command sent
@ -313,15 +324,27 @@ private:
void ProcessEncoderCmd(void);
void ProcessEncoderCmdJoystick(void);
void SendStopAll(void);
void SendConstantForce(INT8 val);
void SendConstantForceY(INT8 val);
void SendSelfCenter(UINT8 val);
void SendFriction(UINT8 val);
void SendVibrate(UINT8 val);
uint8_t ReadADCChannel1();
uint8_t ReadADCChannel2();
uint8_t ReadADCChannel3();
uint8_t ReadADCChannel4();
};
#endif // INCLUDED_DRIVEBOARD_H

View file

@ -2932,6 +2932,7 @@ bool CModel3::LoadGame(const Game &game, const ROMSet &rom_set)
rom_set.get_rom("mpeg_program").CopyTo(dsbROM, 128*1024);
rom_set.get_rom("mpeg_music").CopyTo(mpegROM, 16*0x100000);
rom_set.get_rom("driveboard_program").CopyTo(driveROM, 64*1024);
rom_set.get_rom("ffb_program").CopyTo(driveROM, 64 * 1024);
// Convert PowerPC and 68K ROMs to little endian words
Util::FlipEndian32(crom, 8*0x100000 + 128*0x100000);
@ -3030,6 +3031,15 @@ bool CModel3::LoadGame(const Game &game, const ROMSet &rom_set)
{
if (DriveBoard.Init(driveROM))
return FAIL;
else
DriveBoard.m_boardType = DriveBoard.Wheel;
}
else if (rom_set.get_rom("ffb_program").size)
{
if (DriveBoard.Init(driveROM))
return FAIL;
else
DriveBoard.m_boardType = DriveBoard.Joystick;
}
else
DriveBoard.Init(NULL);
@ -3046,10 +3056,12 @@ bool CModel3::LoadGame(const Game &game, const ROMSet &rom_set)
extra_hw.insert(Util::Format() << "Digital Sound Board (Type " << game.mpeg_board << ")");
if (rom_set.get_rom("driveboard_program").size)
extra_hw.insert("Drive Board");
if (rom_set.get_rom("ffb_program").size)
extra_hw.insert("Joystick FFB Board");
if (game.encryption_key)
extra_hw.insert("Security Board");
if (netboard_present.compare("true")==0)
extra_hw.insert("Net Board");
extra_hw.insert("Net Board");
if (!game.version.empty())
std::cout << " Title: " << game.title << " (" << game.version << ")" << std::endl;
else