From fcf2c8680dcd425babaf09bd7306e355cb3940d4 Mon Sep 17 00:00:00 2001 From: dinkc64 <12570148+dinkc64@users.noreply.github.com> Date: Mon, 26 Feb 2018 01:49:13 +0000 Subject: [PATCH] megadrive: add EA "4-way play" adapter support --- src/burn/burn.h | 1 + src/burn/drv/megadrive/megadrive.cpp | 215 ++++++++++++++++++--------- 2 files changed, 143 insertions(+), 73 deletions(-) diff --git a/src/burn/burn.h b/src/burn/burn.h index a064dec61..4e24c1aab 100644 --- a/src/burn/burn.h +++ b/src/burn/burn.h @@ -572,6 +572,7 @@ void IpsApplyPatches(UINT8* base, char* rom_name); #define HARDWARE_SEGA_MEGADRIVE_PCB_MULAN (42) #define HARDWARE_SEGA_MEGADRIVE_TEAMPLAYER (43) #define HARDWARE_SEGA_MEGADRIVE_TEAMPLAYER_PORT2 (44) +#define HARDWARE_SEGA_MEGADRIVE_FOURWAYPLAY (45) #define HARDWARE_SEGA_MEGADRIVE_SRAM_00400 (0x0100) #define HARDWARE_SEGA_MEGADRIVE_SRAM_00800 (0x0200) diff --git a/src/burn/drv/megadrive/megadrive.cpp b/src/burn/drv/megadrive/megadrive.cpp index 0fd44a0c9..be68d8f66 100644 --- a/src/burn/drv/megadrive/megadrive.cpp +++ b/src/burn/drv/megadrive/megadrive.cpp @@ -42,6 +42,12 @@ #define MAX_CARTRIDGE_SIZE 0xc00000 #define MAX_SRAM_SIZE 0x010000 +#if defined (__GNUC__) && defined (__LIBRETRO__) +#define OPTIMIZE_ATTR __attribute__((optimize("O2"))) +#else +#define OPTIMIZE_ATTR +#endif + // PicoDrive Sek interface static UINT64 SekCycleCnt, SekCycleAim, SekCycleCntDELTA, line_base_cycles; @@ -149,10 +155,21 @@ struct TileStrip INT32 cells; // cells (tiles) to draw (32 col mode doesn't need to update whole 320) }; +struct TeamPlayer { + UINT32 state; + UINT32 counter; + UINT32 table[12]; +}; + struct MegadriveJoyPad { UINT16 pad[8]; - UINT8 padTHPhase[8]; - UINT8 padDelay[8]; + UINT32 padTHPhase[8]; + UINT32 padDelay[8]; + + UINT32 fourwaylatch; // EA "4 way play" adapter + UINT8 fourway[8]; + + TeamPlayer teamplayer[2]; // Sega "team player" 4 port adapter }; static UINT8 *Mem = NULL, *MemEnd = NULL; @@ -195,6 +212,7 @@ UINT8 MegadriveJoy1[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; UINT8 MegadriveJoy2[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; UINT8 MegadriveJoy3[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; UINT8 MegadriveJoy4[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +UINT8 MegadriveJoy5[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; UINT8 MegadriveDIP[2] = {0, 0}; static UINT32 RomNum = 0; @@ -221,6 +239,7 @@ static UINT8 bNoDebug = 0; static INT32 bForce3Button = 0; INT32 psolarmode = 0; // pier solar static INT32 TeamPlayerMode = 0; +static INT32 FourWayPlayMode = 0; void MegadriveCheckHardware() { @@ -377,7 +396,9 @@ static INT32 MemIndex() RamSVid = (UINT16 *) Next; Next += 0x000040 * sizeof(UINT16); // VSRam RamVid = (UINT16 *) Next; Next += 0x008000 * sizeof(UINT16); // Video Ram RamVReg = (struct PicoVideo *)Next; Next += sizeof(struct PicoVideo); - + + JoyPad = (struct MegadriveJoyPad *) Next; Next += sizeof(struct MegadriveJoyPad); + RamEnd = Next; // Keep RamMisc out of the Ram section to keep from getting cleared on reset. @@ -395,8 +416,6 @@ static INT32 MemIndex() HighPreSpr = (INT32 *) Next; Next += (80*2+1) * sizeof(INT32); // slightly preprocessed sprites HighSprZ = (INT8*) Next; Next += (320+8+8); // Z-buffer for accurate sprites and shadow/hilight mode - JoyPad = (struct MegadriveJoyPad *) Next; Next += sizeof(struct MegadriveJoyPad); - MemEnd = Next; return 0; } @@ -1150,7 +1169,7 @@ static INT32 PadRead(INT32 i) { INT32 pad=0,value=0,TH; pad = ~(JoyPad->pad[i]); // Get inverse of pad MXYZ SACB RLDU - TH = RamIO[i+1] & 0x40; + TH = (FourWayPlayMode) ? JoyPad->fourway[i & 0x03] : RamIO[i+1] & 0x40; if (!bForce3Button) { // 6 button gamepad enabled INT32 phase = JoyPad->padTHPhase[i]; @@ -1173,68 +1192,69 @@ static INT32 PadRead(INT32 i) end: // or the bits, which are set as output - value |= RamIO[i+1] & RamIO[i+4]; + if (!FourWayPlayMode) + value |= RamIO[i+1] & RamIO[i+4]; return value; // will mirror later } -static struct { - UINT8 State; - UINT8 Counter; - UINT8 Table[12]; -} teamplayer[2]; - -static void teamplayer_init() +static void PadWrite(INT32 port, UINT8 data, UINT8 *ior) { - INT32 index = 0; - UINT8 port = TeamPlayerMode - 1; - - memset(&teamplayer[port], 0, sizeof(teamplayer[port])); - - for (INT32 i = 0; i < 4; i++) - { - INT32 padnum = ((port << 2) + i) << 4; - - teamplayer[port].Table[index++] = padnum; - teamplayer[port].Table[index++] = padnum | 4; - - if (!bForce3Button) - { - teamplayer[port].Table[index++] = padnum | 8; - } - } + JoyPad->padDelay[port] = 0; + if(!(ior[0] & 0x40) && (data & 0x40)) + JoyPad->padTHPhase[port] ++; + ior[0] = data; } static void teamplayer_reset() { if (!TeamPlayerMode) return; - teamplayer[TeamPlayerMode - 1].State = 0x60; - teamplayer[TeamPlayerMode - 1].Counter = 0; + + INT32 index = 0; + UINT8 port = TeamPlayerMode - 1; + + memset(&JoyPad->teamplayer[port], 0, sizeof(JoyPad->teamplayer[port])); + + for (INT32 i = 0; i < 4; i++) + { + INT32 padnum = ((port << 2) + i) << 4; + + JoyPad->teamplayer[port].table[index++] = padnum; + JoyPad->teamplayer[port].table[index++] = padnum | 4; + + if (!bForce3Button) + { + JoyPad->teamplayer[port].table[index++] = padnum | 8; + } + } + + JoyPad->teamplayer[TeamPlayerMode - 1].state = 0x60; + JoyPad->teamplayer[TeamPlayerMode - 1].counter = 0; } static UINT8 teamplayer_read() { UINT8 port = TeamPlayerMode - 1; - switch (teamplayer[port].Counter) + switch (JoyPad->teamplayer[port].counter) { - case 0: return ((teamplayer[port].State & 0x20) >> 1) | 0x03; + case 0: return ((JoyPad->teamplayer[port].state & 0x20) >> 1) | 0x03; - case 1: return ((teamplayer[port].State & 0x20) >> 1) | 0x0F; + case 1: return ((JoyPad->teamplayer[port].state & 0x20) >> 1) | 0x0F; case 2: - case 3: return ((teamplayer[port].State & 0x20) >> 1); + case 3: return ((JoyPad->teamplayer[port].state & 0x20) >> 1); case 4: case 5: case 6: - case 7: return (((teamplayer[port].State & 0x20) >> 1) | ((bForce3Button) ? 0 : 1)); + case 7: return (((JoyPad->teamplayer[port].state & 0x20) >> 1) | ((bForce3Button) ? 0 : 1)); default: { - UINT8 padnum = teamplayer[port].Table[teamplayer[port].Counter - 8] >> 4; + UINT8 padnum = JoyPad->teamplayer[port].table[JoyPad->teamplayer[port].counter - 8] >> 4; if (TeamPlayerMode == 2) padnum -= 3; - UINT8 retval = 0xf & ~(JoyPad->pad[padnum] >> (teamplayer[port].Table[teamplayer[port].Counter - 8] & 0xf)); + UINT8 retval = 0xf & ~(JoyPad->pad[padnum] >> (JoyPad->teamplayer[port].table[JoyPad->teamplayer[port].counter - 8] & 0xf)); - return (((teamplayer[port].State & 0x20) >> 1) | retval); + return (((JoyPad->teamplayer[port].state & 0x20) >> 1) | retval); } } } @@ -1242,16 +1262,43 @@ static UINT8 teamplayer_read() static void teamplayer_write(UINT8 data, UINT8 mask) { UINT8 port = TeamPlayerMode - 1; - UINT8 state = (teamplayer[port].State & ~mask) | (data & mask); + UINT8 state = (JoyPad->teamplayer[port].state & ~mask) | (data & mask); if (state & 0x40) { - teamplayer[port].Counter = 0; + JoyPad->teamplayer[port].counter = 0; } - else if ((teamplayer[port].State ^ state) & 0x60) { - teamplayer[port].Counter++; + else if ((JoyPad->teamplayer[port].state ^ state) & 0x60) { + JoyPad->teamplayer[port].counter++; } - teamplayer[port].State = state; + JoyPad->teamplayer[port].state = state; +} + +static UINT8 fourwayplay_read(UINT8 port) +{ + switch (port) { + case 0: + if (JoyPad->fourwaylatch & 0x04) return 0x7c; + return PadRead(JoyPad->fourwaylatch & 0x03); + break; + case 1: + return 0x7f; + break; + } + + return 0; +} + +static void fourwayplay_write(UINT8 port, UINT8 data, UINT8 mask) +{ + switch (port) { + case 0: + PadWrite(JoyPad->fourwaylatch & 0x03, data, &JoyPad->fourway[JoyPad->fourwaylatch & 0x03]); + break; + case 1: + JoyPad->fourwaylatch = ((data & mask) >> 4) & 0x07; + break; + } } UINT8 __fastcall MegadriveIOReadByte(UINT32 sekAddress) @@ -1260,7 +1307,7 @@ UINT8 __fastcall MegadriveIOReadByte(UINT32 sekAddress) bprintf(PRINT_NORMAL, _T("IO Attempt to read byte value of location %x\n"), sekAddress); INT32 offset = (sekAddress >> 1) & 0xf; - if (!TeamPlayerMode) { + if (!TeamPlayerMode && !FourWayPlayMode) { // 6-Button Support switch (offset) { case 0: // Get Hardware @@ -1273,8 +1320,8 @@ UINT8 __fastcall MegadriveIOReadByte(UINT32 sekAddress) //bprintf(PRINT_NORMAL, _T("IO Attempt to read byte value of location %x\n"), sekAddress); return RamIO[offset]; } - } else { - // Sega Team Player Support + } else if (TeamPlayerMode || FourWayPlayMode) { + // Sega Team Player & Four Way Play Support switch (offset) { case 0: // Get Hardware return Hardware; @@ -1284,9 +1331,19 @@ UINT8 __fastcall MegadriveIOReadByte(UINT32 sekAddress) UINT8 mask = 0x80 | RamIO[offset + 3]; UINT8 data = 0x7f; if (offset < 3) { - switch (TeamPlayerMode) { - case 1: data = (offset==1) ? teamplayer_read() : 0x7f; break; // teamplayer port 1, nothing port 2 - case 2: data = (offset==2) ? teamplayer_read() : PadRead(0); break; // teamplayer port2, gamepad port 1 + if (TeamPlayerMode) { + switch (TeamPlayerMode) { + case 1: data = (offset==1) ? teamplayer_read() : 0x7f; break; // teamplayer port 1, nothing port 2 + case 2: data = (offset==2) ? teamplayer_read() : PadRead(0); break; // teamplayer port2, gamepad port 1 + } + } + if (FourWayPlayMode) { + switch (offset) { + case 1: + case 2: + data = fourwayplay_read(offset - 1); + break; + } } } return (RamIO[offset] & mask) | (data & ~mask); @@ -1315,28 +1372,28 @@ void __fastcall MegadriveIOWriteByte(UINT32 sekAddress, UINT8 byteValue) INT32 offset = (sekAddress >> 1) & 0xf; - if (!TeamPlayerMode) { + if (!TeamPlayerMode && !FourWayPlayMode) { // 6-Button Support switch( offset ) { case 1: - JoyPad->padDelay[0] = 0; - if(!(RamIO[1] & 0x40) && (byteValue&0x40)) - JoyPad->padTHPhase[0] ++; - break; - case 2: - JoyPad->padDelay[1] = 0; - if(!(RamIO[2] & 0x40) && (byteValue&0x40)) - JoyPad->padTHPhase[1] ++; + case 2: + PadWrite(offset - 1, byteValue, &RamIO[offset]); break; } - } else { + } else if (FourWayPlayMode) { + // EA Four Way Play support + switch (offset) { + case 1: + case 2: + fourwayplay_write(offset-1, byteValue, RamIO[offset + 3]); + break; + } + } else if (TeamPlayerMode) { // Sega Team Player Support switch (offset) { case 1: if (TeamPlayerMode == 2) { // teamplayer port 2, gamepad port 1 - JoyPad->padDelay[0] = 0; - if(!(RamIO[1] & 0x40) && (byteValue&0x40)) - JoyPad->padTHPhase[0] ++; + PadWrite(offset - 1, byteValue, &RamIO[offset]); } else { teamplayer_write(byteValue, RamIO[offset + 3]); } @@ -1360,9 +1417,9 @@ void __fastcall MegadriveIOWriteByte(UINT32 sekAddress, UINT8 byteValue) void __fastcall MegadriveIOWriteWord(UINT32 sekAddress, UINT16 wordValue) { - //if (sekAddress > 0xA1001F) + //if (sekAddress > 0xA1001F) // bprintf(PRINT_NORMAL, _T("IO Attempt to write word value %x to location %x\n"), wordValue, sekAddress); - + MegadriveIOWriteByte(sekAddress, wordValue & 0xff); } @@ -2744,6 +2801,9 @@ static void SetupCustomCartridgeMappers() } switch ((BurnDrvGetHardwareCode() & 0xff)) { + case HARDWARE_SEGA_MEGADRIVE_FOURWAYPLAY: + FourWayPlayMode = 1; + break; case HARDWARE_SEGA_MEGADRIVE_TEAMPLAYER: TeamPlayerMode = 1; break; @@ -2752,12 +2812,16 @@ static void SetupCustomCartridgeMappers() break; default: TeamPlayerMode = 0; + FourWayPlayMode = 0; break; } if (TeamPlayerMode) { bprintf(0, _T("Game supports Sega TeamPlayer 4x Pad in Port %d.\n"), TeamPlayerMode); - teamplayer_init(); + } + + if (FourWayPlayMode) { + bprintf(0, _T("Game supports EA 4-WayPlay 4x Pad in Port 1 & 2.\n")); } } @@ -3358,6 +3422,7 @@ INT32 MegadriveExit() bNoDebug = 0; bForce3Button = 0; TeamPlayerMode = 0; + FourWayPlayMode = 0; psolarmode = 0; @@ -4132,7 +4197,7 @@ static void DrawSpritesFromCache(INT32 *hc, INT32 sh) // Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size // Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 -static void PrepareSprites(INT32 full) +static void OPTIMIZE_ATTR PrepareSprites(INT32 full) { INT32 u=0,link=0,sblocks=0; INT32 table=0; @@ -4503,7 +4568,7 @@ INT32 MegadriveDraw() #define CYCLES_M68K_VINT_LAG 68 #define CYCLES_M68K_ASD 148 -INT32 MegadriveFrame() +INT32 OPTIMIZE_ATTR MegadriveFrame() { if (MegadriveReset) { MegadriveResetDo(); @@ -4511,12 +4576,13 @@ INT32 MegadriveFrame() return 0xdead; // prevent crash because of a call to Reinitialise() in MegadriveResetDo(); } - JoyPad->pad[0] = JoyPad->pad[1] = JoyPad->pad[2] = JoyPad->pad[3] = 0; + JoyPad->pad[0] = JoyPad->pad[1] = JoyPad->pad[2] = JoyPad->pad[3] = JoyPad->pad[4] = 0; for (INT32 i = 0; i < 12; i++) { JoyPad->pad[0] |= (MegadriveJoy1[i] & 1) << i; JoyPad->pad[1] |= (MegadriveJoy2[i] & 1) << i; JoyPad->pad[2] |= (MegadriveJoy3[i] & 1) << i; JoyPad->pad[3] |= (MegadriveJoy4[i] & 1) << i; + JoyPad->pad[4] |= (MegadriveJoy5[i] & 1) << i; } SekCyclesNewFrame(); // for sound sync @@ -4588,6 +4654,11 @@ INT32 MegadriveFrame() // pad delay (for 6 button pads) if(JoyPad->padDelay[0]++ > 25) JoyPad->padTHPhase[0] = 0; if(JoyPad->padDelay[1]++ > 25) JoyPad->padTHPhase[1] = 0; + + if (FourWayPlayMode) { + if(JoyPad->padDelay[2]++ > 25) JoyPad->padTHPhase[2] = 0; // fourwayplay + if(JoyPad->padDelay[3]++ > 25) JoyPad->padTHPhase[3] = 0; // " + } } // H-Interrupts: @@ -4734,8 +4805,6 @@ INT32 MegadriveScan(INT32 nAction, INT32 *pnMin) SCAN_VAR(z80_cycle_aim); SCAN_VAR(last_z80_sync); - SCAN_VAR(teamplayer); - BurnRandomScan(nAction); }