summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/slapstic.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/slapstic.c')
-rw-r--r--src/mame/machine/slapstic.c1174
1 files changed, 1174 insertions, 0 deletions
diff --git a/src/mame/machine/slapstic.c b/src/mame/machine/slapstic.c
new file mode 100644
index 00000000000..189b23d50a0
--- /dev/null
+++ b/src/mame/machine/slapstic.c
@@ -0,0 +1,1174 @@
+/*************************************************************************
+
+ Atari Slapstic decoding helper
+
+**************************************************************************
+
+ Atari Slapstic FAQ
+ Version 1.12
+ by Aaron Giles and Frank Palazzolo
+ 9/12/2002
+
+
+ What is a slapstic?
+
+ The slapstic was a security chip made by Atari, which was used for
+ bank switching and security in several coin-operated video games from
+ 1984 through 1990.
+
+
+ What is a SLOOP?
+
+ The SLOOP (or "SLOOPstic") is a follow-on chip to the slapstic. It
+ provides a similar type of security, but is programmed onto a GAL6001,
+ rather than a custom part. It was created because Atari was running
+ out of slapstics to use in their games, and the original masks for the
+ slapstic had been lost by the company that manufactured them. A separate
+ FAQ for this chip is planned for the future.
+
+
+ How do I identify a slapstic chip on my board?
+
+ Look for a small, socketed 20-pin DIP on the board. The number on
+ the chip will be 137412-1xx.
+
+
+ Are slapstic chips interchangeable?
+
+ Sadly, no. They were designed to prevent operators from burning
+ new EPROMs and "upgrading" their PCBs to a new game without buying
+ the necessary kits from Atari. For example, the five System 1 games
+ each used a different slapstic, so that you couldn't take, say,
+ a <b>Marble Madness</b> machine, burn new EPROMs, and convert it into
+ an <b>Indiana Jones</b>.
+
+ That said, however, there are two pairs of the slapstics that appear
+ to be functionally identical, despite the fact that they have
+ different part numbers:
+
+ 137412-103 (<b>Marble Madness</b>) appears to be functionally identical
+ to 137412-110 (<b>Road Blasters</b> & <b>APB</b>)
+
+ 137412-106 (<b>Gauntlet II</b>) appears to be functionally identical
+ to 137412-109 (<b>Championship Sprint</b>)
+
+ Note, however, that I have not tried these swaps to confirm that they
+ work. Your mileage may vary.
+
+
+ How many different slapstics are there?
+
+ All told, a total of 13 actual slapstics have been found. However,
+ there are gaps in the numbering which indicate that more may exist.
+
+
+ Do all slapstics work the same?
+
+ In general, yes. However, matters are complicated by the existence
+ of multiple revisions of the chip design:
+
+ SLAPSTIC Part #137412-101 through 137412-110
+ SLAPSTIC-2 Part #137412-111 through 137412-118
+
+ In the simplest case, both revs act the same. However, they differ
+ in how the more complex modes of operation are used.
+
+
+ How is the slapstic connected to the game?
+
+ The slapstic generally sits between the CPU's address bus and one
+ of the program ROMs. Here's a pinout:
+
+ A9 1 +-v-+ 20 A8
+ A10 2 | | 19 A7
+ A11 3 | | 18 A6
+ A12 4 | | 17 A5
+ A13 5 | | 16 A4
+ /CS 6 | | 15 A3
+ CLK 7 | | 14 A2
+ VCC 8 | | 13 A1
+ BS1 9 | | 12 A0
+ BS0 10 +---+ 11 GND
+
+ A0-A13 are the address lines from the CPU. CLK and /CS together
+ trigger a state change. BS0 and BS1 are the bank select outputs,
+ which usually connect to the protected program ROM in place of
+ two address lines (traditionally A12 and A13).
+
+ Most slapstics were used on 68000 or T-11 based games, which had
+ a 16-bit address bus. This meant that A0-A13 on the slapstic were
+ generally connected to A1-A14 on the CPU. However, two 8-bit
+ games (Tetris and Empire Strikes Back) used the slapstic as well.
+ This slapstic (#101) has a slightly different pinout, though it
+ operates similarly to the others in its class.
+
+ A8 1 +-v-+ 20 A7
+ A9 2 | | 19 A6
+ A10 3 | | 18 A5
+ A11 4 | | 17 A4
+ A12 5 | | 16 A3
+ /CS 6 | | 15 A2
+ CLK 7 | | 14 A1
+ VCC 8 | | 13 A0
+ /BS1 9 | | 12 GND
+ BS1 10 +---+ 11 BS0
+
+
+ Which games used slapstics?
+
+ 137412-101 Empire Strikes Back
+ 137412-101 Tetris
+ 137412-103 Marble Madness
+ 137412-104 Gauntlet
+ 137412-105 Paperboy
+ 137412-105 Indiana Jones & the Temple of Doom
+ 137412-106 Gauntlet II
+ 137412-107 2-Player Gauntlet
+ 137412-107 Peter Packrat
+ 137412-107 720 Degrees
+ 137412-107 Xybots
+ 137412-108 Road Runner
+ 137412-108 Super Sprint
+ 137412-109 Championship Sprint
+ 137412-109 Road Blasters (some versions)
+ 137412-110 Road Blasters
+ 137412-110 APB
+ 137412-111 Pit Fighter
+ 137412-112 Pit Fighter (Europe)
+ 137412-113 Unknown (Europe)
+ 137412-115 Race Drivin' DSK board
+ 137412-116 Hydra
+ 137412-116 Tournament Cyberball 2072
+ 137412-117 Race Drivin' main board
+ 137412-118 Rampart
+ 137412-118 Vindicators Part II
+
+
+ How does the slapstic work?
+
+ On power-up, the slapstic starts by pointing to bank 0 or bank 3.
+ After that, certain sequences of addresses will trigger a bankswitch.
+ Each sequence begins with an access to location $0000, followed by one
+ or more special addresses.
+
+ Each slapstic has a 'simple' mode of bankswitching, consisting of an
+ access to $0000 followed by an access to one of four bank addresses.
+ Other accesses are allowed in between these two accesses without
+ affecting the outcome.
+
+ Additionally, each slapstic has a trickier variant of the
+ bankswitching, which requires an access to $0000, followed by accesses
+ to two specific addresses, followed by one of four alternate bank
+ addresses. All three accesses following the $0000 must occur in
+ sequence with no interruptions, or else the sequence is invalidated.
+
+ Finally, each slapstic has a mechanism for modifying the value of the
+ current bank. Earlier chips (101-110) allowed you to twiddle the
+ specific bits of the bank number, clearing or setting bits 0 and 1
+ independently. Later chips (111-118) provided a mechanism of adding
+ 1, 2, or 3 to the number of the current bank.
+
+ Surprisingly, the slapstic appears to have used DRAM cells to store
+ the current bank. After 5 or 6 seconds without a clock, the chip
+ reverts to the default bank, with the chip reset (bank select
+ addresses are enabled). Typically, the slapstic region is accessed
+ often enough to cause a problem.
+
+ For full details, see the MAME source code.
+
+*************************************************************************/
+
+#include "driver.h"
+#include "slapstic.h"
+#include "cpu/m68000/m68000.h"
+
+
+/*************************************
+ *
+ * Structure of slapstic params
+ *
+ *************************************/
+
+struct mask_value
+{
+ int mask, value;
+};
+
+
+struct slapstic_data
+{
+ int bankstart;
+ int bank[4];
+
+ struct mask_value alt1;
+ struct mask_value alt2;
+ struct mask_value alt3;
+ struct mask_value alt4;
+ int altshift;
+
+ struct mask_value bit1;
+ struct mask_value bit2c0;
+ struct mask_value bit2s0;
+ struct mask_value bit2c1;
+ struct mask_value bit2s1;
+ struct mask_value bit3;
+
+ struct mask_value add1;
+ struct mask_value add2;
+ struct mask_value addplus1;
+ struct mask_value addplus2;
+ struct mask_value add3;
+};
+
+
+
+/*************************************
+ *
+ * Shorthand
+ *
+ *************************************/
+
+#define UNKNOWN 0xffff
+#define NO_BITWISE \
+ { UNKNOWN,UNKNOWN }, \
+ { UNKNOWN,UNKNOWN }, \
+ { UNKNOWN,UNKNOWN }, \
+ { UNKNOWN,UNKNOWN }, \
+ { UNKNOWN,UNKNOWN }, \
+ { UNKNOWN,UNKNOWN }
+#define NO_ADDITIVE \
+ { UNKNOWN,UNKNOWN }, \
+ { UNKNOWN,UNKNOWN }, \
+ { UNKNOWN,UNKNOWN }, \
+ { UNKNOWN,UNKNOWN }, \
+ { UNKNOWN,UNKNOWN }
+
+#define MATCHES_MASK_VALUE(val, maskval) (((val) & (maskval).mask) == (maskval).value)
+
+
+/*************************************
+ *
+ * Constants
+ *
+ *************************************/
+
+enum state_type
+{
+ DISABLED,
+ ENABLED,
+ ALTERNATE1,
+ ALTERNATE2,
+ ALTERNATE3,
+ BITWISE1,
+ BITWISE2,
+ BITWISE3,
+ ADDITIVE1,
+ ADDITIVE2,
+ ADDITIVE3
+};
+
+#define LOG_SLAPSTIC 0
+
+
+
+/*************************************
+ *
+ * Slapstic definitions
+ *
+ *************************************/
+
+/* slapstic 137412-101: Empire Strikes Back/Tetris (NOT confirmed) */
+static struct slapstic_data slapstic101 =
+{
+ /* basic banking */
+ 3, /* starting bank */
+ { 0x0080,0x0090,0x00a0,0x00b0 },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,UNKNOWN }, /* 1st mask/value in sequence */
+ { 0x1fff,0x1dfe }, /* 2nd mask/value in sequence */
+ { 0x1ffc,0x1b5c }, /* 3rd mask/value in sequence */
+ { 0x1fcf,0x0080 }, /* 4th mask/value in sequence */
+ 0, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ { 0x1ff0,0x1540 }, /* 1st mask/value in sequence */
+ { 0x1ff3,0x1540 }, /* clear bit 0 value */
+ { 0x1ff3,0x1541 }, /* set bit 0 value */
+ { 0x1ff3,0x1542 }, /* clear bit 1 value */
+ { 0x1ff3,0x1543 }, /* set bit 1 value */
+ { 0x1ff8,0x1550 }, /* final mask/value in sequence */
+
+ /* additive banking */
+ NO_ADDITIVE
+};
+
+
+/* slapstic 137412-103: Marble Madness (confirmed) */
+static struct slapstic_data slapstic103 =
+{
+ /* basic banking */
+ 3, /* starting bank */
+ { 0x0040,0x0050,0x0060,0x0070 },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x002d }, /* 1st mask/value in sequence */
+ { 0x3fff,0x3d14 }, /* 2nd mask/value in sequence */
+ { 0x3ffc,0x3d24 }, /* 3rd mask/value in sequence */
+ { 0x3fcf,0x0040 }, /* 4th mask/value in sequence */
+ 0, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ { 0x3ff0,0x34c0 }, /* 1st mask/value in sequence */
+ { 0x3ff3,0x34c0 }, /* clear bit 0 value */
+ { 0x3ff3,0x34c1 }, /* set bit 0 value */
+ { 0x3ff3,0x34c2 }, /* clear bit 1 value */
+ { 0x3ff3,0x34c3 }, /* set bit 1 value */
+ { 0x3ff8,0x34d0 }, /* final mask/value in sequence */
+
+ /* additive banking */
+ NO_ADDITIVE
+};
+
+
+/* slapstic 137412-104: Gauntlet (confirmed) */
+static struct slapstic_data slapstic104 =
+{
+ /* basic banking */
+ 3, /* starting bank */
+ { 0x0020,0x0028,0x0030,0x0038 },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x0069 }, /* 1st mask/value in sequence */
+ { 0x3fff,0x3735 }, /* 2nd mask/value in sequence */
+ { 0x3ffc,0x3764 }, /* 3rd mask/value in sequence */
+ { 0x3fe7,0x0020 }, /* 4th mask/value in sequence */
+ 0, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ { 0x3ff0,0x3d90 }, /* 1st mask/value in sequence */
+ { 0x3ff3,0x3d90 }, /* clear bit 0 value */
+ { 0x3ff3,0x3d91 }, /* set bit 0 value */
+ { 0x3ff3,0x3d92 }, /* clear bit 1 value */
+ { 0x3ff3,0x3d93 }, /* set bit 1 value */
+ { 0x3ff8,0x3da0 }, /* final mask/value in sequence */
+
+ /* additive banking */
+ NO_ADDITIVE
+};
+
+
+/* slapstic 137412-105: Indiana Jones/Paperboy (confirmed) */
+static struct slapstic_data slapstic105 =
+{
+ /* basic banking */
+ 3, /* starting bank */
+ { 0x0010,0x0014,0x0018,0x001c },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x003d }, /* 1st mask/value in sequence */
+ { 0x3fff,0x0092 }, /* 2nd mask/value in sequence */
+ { 0x3ffc,0x00a4 }, /* 3rd mask/value in sequence */
+ { 0x3ff3,0x0010 }, /* 4th mask/value in sequence */
+ 0, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ { 0x3ff0,0x35b0 }, /* 1st mask/value in sequence */
+ { 0x3ff3,0x35b0 }, /* clear bit 0 value */
+ { 0x3ff3,0x35b1 }, /* set bit 0 value */
+ { 0x3ff3,0x35b2 }, /* clear bit 1 value */
+ { 0x3ff3,0x35b3 }, /* set bit 1 value */
+ { 0x3ff8,0x35c0 }, /* final mask/value in sequence */
+
+ /* additive banking */
+ NO_ADDITIVE
+};
+
+
+/* slapstic 137412-106: Gauntlet II (confirmed) */
+static struct slapstic_data slapstic106 =
+{
+ /* basic banking */
+ 3, /* starting bank */
+ { 0x0008,0x000a,0x000c,0x000e },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x002b }, /* 1st mask/value in sequence */
+ { 0x3fff,0x0052 }, /* 2nd mask/value in sequence */
+ { 0x3ffc,0x0064 }, /* 3rd mask/value in sequence */
+ { 0x3ff9,0x0008 }, /* 4th mask/value in sequence */
+ 0, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ { 0x3ff0,0x3da0 }, /* 1st mask/value in sequence */
+ { 0x3ff3,0x3da0 }, /* clear bit 0 value */
+ { 0x3ff3,0x3da1 }, /* set bit 0 value */
+ { 0x3ff3,0x3da2 }, /* clear bit 1 value */
+ { 0x3ff3,0x3da3 }, /* set bit 1 value */
+ { 0x3ff8,0x3db0 }, /* final mask/value in sequence */
+
+ /* additive banking */
+ NO_ADDITIVE
+};
+
+
+/* slapstic 137412-107: Peter Packrat/Xybots/2p Gauntlet/720 (confirmed) */
+static struct slapstic_data slapstic107 =
+{
+ /* basic banking */
+ 3, /* starting bank */
+ { 0x0018,0x001a,0x001c,0x001e },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x006b }, /* 1st mask/value in sequence */
+ { 0x3fff,0x3d52 }, /* 2nd mask/value in sequence */
+ { 0x3ffc,0x3d64 }, /* 3rd mask/value in sequence */
+ { 0x3ff9,0x0018 }, /* 4th mask/value in sequence */
+ 0, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ { 0x3ff0,0x00a0 }, /* 1st mask/value in sequence */
+ { 0x3ff3,0x00a0 }, /* clear bit 0 value */
+ { 0x3ff3,0x00a1 }, /* set bit 0 value */
+ { 0x3ff3,0x00a2 }, /* clear bit 1 value */
+ { 0x3ff3,0x00a3 }, /* set bit 1 value */
+ { 0x3ff8,0x00b0 }, /* final mask/value in sequence */
+
+ /* additive banking */
+ NO_ADDITIVE
+};
+
+
+/* slapstic 137412-108: Road Runner/Super Sprint (confirmed) */
+static struct slapstic_data slapstic108 =
+{
+ /* basic banking */
+ 3, /* starting bank */
+ { 0x0028,0x002a,0x002c,0x002e },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x001f }, /* 1st mask/value in sequence */
+ { 0x3fff,0x3772 }, /* 2nd mask/value in sequence */
+ { 0x3ffc,0x3764 }, /* 3rd mask/value in sequence */
+ { 0x3ff9,0x0028 }, /* 4th mask/value in sequence */
+ 0, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ { 0x3ff0,0x0060 }, /* 1st mask/value in sequence */
+ { 0x3ff3,0x0060 }, /* clear bit 0 value */
+ { 0x3ff3,0x0061 }, /* set bit 0 value */
+ { 0x3ff3,0x0062 }, /* clear bit 1 value */
+ { 0x3ff3,0x0063 }, /* set bit 1 value */
+ { 0x3ff8,0x0070 }, /* final mask/value in sequence */
+
+ /* additive banking */
+ NO_ADDITIVE
+};
+
+
+/* slapstic 137412-109: Championship Sprint/Road Blasters (confirmed) */
+static struct slapstic_data slapstic109 =
+{
+ /* basic banking */
+ 3, /* starting bank */
+ { 0x0008,0x000a,0x000c,0x000e },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x002b }, /* 1st mask/value in sequence */
+ { 0x3fff,0x0052 }, /* 2nd mask/value in sequence */
+ { 0x3ffc,0x0064 }, /* 3rd mask/value in sequence */
+ { 0x3ff9,0x0008 }, /* 4th mask/value in sequence */
+ 0, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ { 0x3ff0,0x3da0 }, /* 1st mask/value in sequence */
+ { 0x3ff3,0x3da0 }, /* clear bit 0 value */
+ { 0x3ff3,0x3da1 }, /* set bit 0 value */
+ { 0x3ff3,0x3da2 }, /* clear bit 1 value */
+ { 0x3ff3,0x3da3 }, /* set bit 1 value */
+ { 0x3ff8,0x3db0 }, /* final mask/value in sequence */
+
+ /* additive banking */
+ NO_ADDITIVE
+};
+
+
+/* slapstic 137412-110: Road Blasters/APB (confirmed) */
+static struct slapstic_data slapstic110 =
+{
+ /* basic banking */
+ 3, /* starting bank */
+ { 0x0040,0x0050,0x0060,0x0070 },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x002d }, /* 1st mask/value in sequence */
+ { 0x3fff,0x3d14 }, /* 2nd mask/value in sequence */
+ { 0x3ffc,0x3d24 }, /* 3rd mask/value in sequence */
+ { 0x3fcf,0x0040 }, /* 4th mask/value in sequence */
+ 0, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ { 0x3ff0,0x34c0 }, /* 1st mask/value in sequence */
+ { 0x3ff3,0x34c0 }, /* clear bit 0 value */
+ { 0x3ff3,0x34c1 }, /* set bit 0 value */
+ { 0x3ff3,0x34c2 }, /* clear bit 1 value */
+ { 0x3ff3,0x34c3 }, /* set bit 1 value */
+ { 0x3ff8,0x34d0 }, /* final mask/value in sequence */
+
+ /* additive banking */
+ NO_ADDITIVE
+};
+
+
+
+/*************************************
+ *
+ * Slapstic-2 definitions
+ *
+ *************************************/
+
+/* slapstic 137412-111: Pit Fighter (confirmed) */
+static struct slapstic_data slapstic111 =
+{
+ /* basic banking */
+ 0, /* starting bank */
+ { 0x0042,0x0052,0x0062,0x0072 },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x000a }, /* 1st mask/value in sequence */
+ { 0x3fff,0x28a4 }, /* 2nd mask/value in sequence */
+ { 0x0784,0x0080 }, /* 3rd mask/value in sequence */
+ { 0x3fcf,0x0042 }, /* 4th mask/value in sequence */
+ 0, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ NO_BITWISE,
+
+ /* additive banking */
+ { 0x3fff,0x00a1 }, /* 1st mask/value in sequence */
+ { 0x3fff,0x00a2 }, /* 2nd mask/value in sequence */
+ { 0x3c4f,0x284d }, /* +1 mask/value */
+ { 0x3a5f,0x285d }, /* +2 mask/value */
+ { 0x3ff8,0x2800 } /* final mask/value in sequence */
+};
+
+
+/* slapstic 137412-112: Pit Fighter (Japan) (confirmed) */
+static struct slapstic_data slapstic112 =
+{
+ /* basic banking */
+ 0, /* starting bank */
+ { 0x002c,0x003c,0x006c,0x007c },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x0014 }, /* 1st mask/value in sequence */
+ { 0x3fff,0x29a0 }, /* 2nd mask/value in sequence */
+ { 0x0073,0x0010 }, /* 3rd mask/value in sequence */
+ { 0x3faf,0x002c }, /* 4th mask/value in sequence */
+ 2, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ NO_BITWISE,
+
+ /* additive banking */
+ { 0x3fff,0x2dce }, /* 1st mask/value in sequence */
+ { 0x3fff,0x2dcf }, /* 2nd mask/value in sequence */
+ { 0x3def,0x15e2 }, /* +1 mask/value */
+ { 0x3fbf,0x15a2 }, /* +2 mask/value */
+ { 0x3ffc,0x1450 } /* final mask/value in sequence */
+};
+
+
+/* slapstic 137412-113: Unknown (Europe) (confirmed) */
+static struct slapstic_data slapstic113 =
+{
+ /* basic banking */
+ 0, /* starting bank */
+ { 0x0008,0x0018,0x0028,0x0038 },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x0059 }, /* 1st mask/value in sequence */
+ { 0x3fff,0x11a5 }, /* 2nd mask/value in sequence */
+ { 0x0860,0x0800 }, /* 3rd mask/value in sequence */
+ { 0x3fcf,0x0008 }, /* 4th mask/value in sequence */
+ 3, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ NO_BITWISE,
+
+ /* additive banking */
+ { 0x3fff,0x049b }, /* 1st mask/value in sequence */
+ { 0x3fff,0x049c }, /* 2nd mask/value in sequence */
+ { 0x3fcf,0x3ec7 }, /* +1 mask/value */
+ { 0x3edf,0x3ed7 }, /* +2 mask/value */
+ { 0x3fff,0x3fb2 } /* final mask/value in sequence */
+};
+
+
+/* slapstic 137412-114: Unknown (Europe) (unconfirmed) */
+static struct slapstic_data slapstic114 =
+{
+ /* basic banking */
+ 0, /* starting bank */
+ { 0x0040,0x0048,0x0050,0x0058 },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x0016 }, /* 1st mask/value in sequence */
+ { 0x3fff,0x24de }, /* 2nd mask/value in sequence */
+ { 0x3871,0x0000 }, /* 3rd mask/value in sequence */
+ { 0x3fe7,0x0040 }, /* 4th mask/value in sequence */
+ 1, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ NO_BITWISE,
+
+ /* additive banking */
+ { 0x3fff,0x0ab7 }, /* 1st mask/value in sequence */
+ { 0x3fff,0x0ab8 }, /* 2nd mask/value in sequence */
+ { 0x3f63,0x0d40 }, /* +1 mask/value */
+ { 0x3fd9,0x0dc8 }, /* +2 mask/value */
+ { 0x3fff,0x0ab0 } /* final mask/value in sequence */
+};
+
+
+/* slapstic 137412-115: Race Drivin' DSK board (confirmed) */
+static struct slapstic_data slapstic115 =
+{
+ /* basic banking */
+ 0, /* starting bank */
+ { 0x0020,0x0022,0x0024,0x0026 },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x0054 }, /* 1st mask/value in sequence */
+ { 0x3fff,0x3e01 }, /* 2nd mask/value in sequence */
+ { 0x3879,0x0029 }, /* 3rd mask/value in sequence */
+ { 0x3ff9,0x0020 }, /* 4th mask/value in sequence */
+ 1, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ NO_BITWISE,
+
+ /* additive banking */
+ { 0x3fff,0x2591 }, /* 1st mask/value in sequence */
+ { 0x3fff,0x2592 }, /* 2nd mask/value in sequence */
+ { 0x3fe6,0x3402 }, /* +1 mask/value */
+ { 0x3fb4,0x3410 }, /* +2 mask/value */
+ { 0x3fff,0x34a2 } /* final mask/value in sequence */
+};
+
+
+/* slapstic 137412-116: Hydra (confirmed) */
+static struct slapstic_data slapstic116 =
+{
+ /* basic banking */
+ 0, /* starting bank */
+ { 0x0044,0x004c,0x0054,0x005c },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x0069 }, /* 1st mask/value in sequence */
+ { 0x3fff,0x2bab }, /* 2nd mask/value in sequence */
+ { 0x387c,0x0808 }, /* 3rd mask/value in sequence */
+ { 0x3fe7,0x0044 }, /* 4th mask/value in sequence */
+ 0, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ NO_BITWISE,
+
+ /* additive banking */
+ { 0x3fff,0x3f7c }, /* 1st mask/value in sequence */
+ { 0x3fff,0x3f7d }, /* 2nd mask/value in sequence */
+ { 0x3db2,0x3c12 }, /* +1 mask/value */
+ { 0x3fe3,0x3e43 }, /* +2 mask/value */
+ { 0x3fff,0x2ba8 } /* final mask/value in sequence */
+};
+
+
+/* slapstic 137412-117: Race Drivin' main board (confirmed) */
+static struct slapstic_data slapstic117 =
+{
+ /* basic banking */
+ 0, /* starting bank */
+ { 0x0008,0x001a,0x002c,0x003e },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x007d }, /* 1st mask/value in sequence */
+ { 0x3fff,0x3580 }, /* 2nd mask/value in sequence */
+ { 0x0079,0x0020 }, /* 3rd mask/value in sequence */
+ { 0x3fc9,0x0008 }, /* 4th mask/value in sequence */
+ 1, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ NO_BITWISE,
+
+ /* additive banking */
+ { 0x3fff,0x0676 }, /* 1st mask/value in sequence */
+ { 0x3fff,0x0677 }, /* 2nd mask/value in sequence */
+ { 0x3e62,0x1a42 }, /* +1 mask/value */
+ { 0x3e35,0x1a11 }, /* +2 mask/value */
+ { 0x3fff,0x1a42 } /* final mask/value in sequence */
+};
+
+
+/* slapstic 137412-118: Rampart/Vindicators II (confirmed) */
+static struct slapstic_data slapstic118 =
+{
+ /* basic banking */
+ 0, /* starting bank */
+ { 0x0014,0x0034,0x0054,0x0074 },/* bank select values */
+
+ /* alternate banking */
+ { 0x007f,0x0002 }, /* 1st mask/value in sequence */
+ { 0x3fff,0x1950 }, /* 2nd mask/value in sequence */
+ { 0x0067,0x0020 }, /* 3rd mask/value in sequence */
+ { 0x3f9f,0x0014 }, /* 4th mask/value in sequence */
+ 3, /* shift to get bank from 3rd */
+
+ /* bitwise banking */
+ NO_BITWISE,
+
+ /* additive banking */
+ { 0x3fff,0x1958 }, /* 1st mask/value in sequence */
+ { 0x3fff,0x1959 }, /* 2nd mask/value in sequence */
+ { 0x3f73,0x3052 }, /* +1 mask/value */
+ { 0x3f67,0x3042 }, /* +2 mask/value */
+ { 0x3ff8,0x30e0 } /* final mask/value in sequence */
+};
+
+
+
+/*************************************
+ *
+ * Master slapstic table
+ *
+ *************************************/
+
+/* master table */
+static struct slapstic_data *slapstic_table[] =
+{
+ &slapstic101, /* NOT confirmed! */
+ NULL, /* never seen */
+ &slapstic103,
+ &slapstic104,
+ &slapstic105,
+ &slapstic106,
+ &slapstic107,
+ &slapstic108,
+ &slapstic109,
+ &slapstic110,
+ &slapstic111,
+ &slapstic112,
+ &slapstic113,
+ &slapstic114,
+ &slapstic115,
+ &slapstic116,
+ &slapstic117,
+ &slapstic118
+};
+
+
+
+/*************************************
+ *
+ * Statics
+ *
+ *************************************/
+
+static enum state_type state;
+static INT8 current_bank;
+static int access_68k;
+
+static INT8 alt_bank;
+static INT8 bit_bank;
+static INT8 add_bank;
+static UINT8 bit_xor;
+
+static struct slapstic_data slapstic;
+
+
+#if LOG_SLAPSTIC
+ static void slapstic_log(offs_t offset);
+ static FILE *slapsticlog;
+#else
+ #define slapstic_log(o)
+#endif
+
+
+
+/*************************************
+ *
+ * Initialization
+ *
+ *************************************/
+
+void slapstic_init(int chip)
+{
+ /* only a small number of chips are known to exist */
+ if (chip < 101 || chip > 118)
+ return;
+
+ /* set up the parameters */
+ if (!slapstic_table[chip - 101])
+ return;
+ slapstic = *slapstic_table[chip - 101];
+
+ /* reset the chip */
+ slapstic_reset();
+
+ /* see if we're 68k or 6502/6809 based */
+ access_68k = (Machine->drv->cpu[0].type != CPU_M6809 &&
+ Machine->drv->cpu[0].type != CPU_M6502);
+}
+
+
+void slapstic_reset(void)
+{
+ /* reset the chip */
+ state = DISABLED;
+
+ /* the 111 and later chips seem to reset to bank 0 */
+ current_bank = slapstic.bankstart;
+}
+
+
+
+/*************************************
+ *
+ * Returns active bank without tweaking
+ *
+ *************************************/
+
+int slapstic_bank(void)
+{
+ return current_bank;
+}
+
+
+
+/*************************************
+ *
+ * Kludge to catch alt seqeuences
+ *
+ *************************************/
+
+static int alt2_kludge(offs_t offset)
+{
+ /* 68k case is fairly complex: we need to look for special triplets */
+ if (access_68k)
+ {
+ UINT32 pc = activecpu_get_previouspc();
+
+ /* first verify that the prefetched PC matches the first alternate */
+ if (MATCHES_MASK_VALUE((pc + 2) >> 1, slapstic.alt1))
+ {
+ /* now look for a move.w (An),(An) or cmpm.w (An)+,(An)+ */
+ UINT16 opcode = cpu_readop16(pc & 0xffffff);
+ if ((opcode & 0xf1f8) == 0x3090 || (opcode & 0xf1f8) == 0xb148)
+ {
+ /* fetch the value of the register for the second operand, and see */
+ /* if it matches the third alternate */
+ UINT32 regval = activecpu_get_reg(M68K_A0 + ((opcode >> 9) & 7)) >> 1;
+ if (MATCHES_MASK_VALUE(regval, slapstic.alt3))
+ {
+ alt_bank = (regval >> slapstic.altshift) & 3;
+ return ALTERNATE3;
+ }
+ }
+ }
+
+ /* if there's no second memory hit within this instruction, the next */
+ /* opcode fetch will botch the operation, so just fall back to */
+ /* the enabled state */
+ return ENABLED;
+ }
+
+ /* kludge for ESB */
+ return ALTERNATE2;
+}
+
+
+
+/*************************************
+ *
+ * Call this *after* every access
+ *
+ *************************************/
+
+int slapstic_tweak(offs_t offset)
+{
+ /* reset is universal */
+ if (offset == 0x0000)
+ {
+ state = ENABLED;
+ }
+
+ /* otherwise, use the state machine */
+ else
+ {
+ switch (state)
+ {
+ /* DISABLED state: everything is ignored except a reset */
+ case DISABLED:
+ break;
+
+ /* ENABLED state: the chip has been activated and is ready for a bankswitch */
+ case ENABLED:
+
+ /* check for request to enter bitwise state */
+ if (MATCHES_MASK_VALUE(offset, slapstic.bit1))
+ {
+ state = BITWISE1;
+ }
+
+ /* check for request to enter additive state */
+ else if (MATCHES_MASK_VALUE(offset, slapstic.add1))
+ {
+ state = ADDITIVE1;
+ }
+
+ /* check for request to enter alternate state */
+ else if (MATCHES_MASK_VALUE(offset, slapstic.alt1))
+ {
+ state = ALTERNATE1;
+ }
+
+ /* special kludge for catching the second alternate address if */
+ /* the first one was missed (since it's usually an opcode fetch) */
+ else if (MATCHES_MASK_VALUE(offset, slapstic.alt2))
+ {
+ state = alt2_kludge(offset);
+ }
+
+ /* check for standard bankswitches */
+ else if (offset == slapstic.bank[0])
+ {
+ state = DISABLED;
+ current_bank = 0;
+ }
+ else if (offset == slapstic.bank[1])
+ {
+ state = DISABLED;
+ current_bank = 1;
+ }
+ else if (offset == slapstic.bank[2])
+ {
+ state = DISABLED;
+ current_bank = 2;
+ }
+ else if (offset == slapstic.bank[3])
+ {
+ state = DISABLED;
+ current_bank = 3;
+ }
+ break;
+
+ /* ALTERNATE1 state: look for alternate2 offset, or else fall back to ENABLED */
+ case ALTERNATE1:
+ if (MATCHES_MASK_VALUE(offset, slapstic.alt2))
+ {
+ state = ALTERNATE2;
+ }
+ else
+ {
+ state = ENABLED;
+ }
+ break;
+
+ /* ALTERNATE2 state: look for altbank offset, or else fall back to ENABLED */
+ case ALTERNATE2:
+ if (MATCHES_MASK_VALUE(offset, slapstic.alt3))
+ {
+ state = ALTERNATE3;
+ alt_bank = (offset >> slapstic.altshift) & 3;
+ }
+ else
+ {
+ state = ENABLED;
+ }
+ break;
+
+ /* ALTERNATE3 state: wait for the final value to finish the transaction */
+ case ALTERNATE3:
+ if (MATCHES_MASK_VALUE(offset, slapstic.alt4))
+ {
+ state = DISABLED;
+ current_bank = alt_bank;
+ }
+ break;
+
+ /* BITWISE1 state: waiting for a bank to enter the BITWISE state */
+ case BITWISE1:
+ if (offset == slapstic.bank[0] || offset == slapstic.bank[1] ||
+ offset == slapstic.bank[2] || offset == slapstic.bank[3])
+ {
+ state = BITWISE2;
+ bit_bank = current_bank;
+ bit_xor = 0;
+ }
+ break;
+
+ /* BITWISE2 state: watch for twiddling and the escape mechanism */
+ case BITWISE2:
+
+ /* check for clear bit 0 case */
+ if (MATCHES_MASK_VALUE(offset ^ bit_xor, slapstic.bit2c0))
+ {
+ bit_bank &= ~1;
+ bit_xor ^= 3;
+ }
+
+ /* check for set bit 0 case */
+ else if (MATCHES_MASK_VALUE(offset ^ bit_xor, slapstic.bit2s0))
+ {
+ bit_bank |= 1;
+ bit_xor ^= 3;
+ }
+
+ /* check for clear bit 1 case */
+ else if (MATCHES_MASK_VALUE(offset ^ bit_xor, slapstic.bit2c1))
+ {
+ bit_bank &= ~2;
+ bit_xor ^= 3;
+ }
+
+ /* check for set bit 1 case */
+ else if (MATCHES_MASK_VALUE(offset ^ bit_xor, slapstic.bit2s1))
+ {
+ bit_bank |= 2;
+ bit_xor ^= 3;
+ }
+
+ /* check for escape case */
+ else if (MATCHES_MASK_VALUE(offset, slapstic.bit3))
+ {
+ state = BITWISE3;
+ }
+ break;
+
+ /* BITWISE3 state: waiting for a bank to seal the deal */
+ case BITWISE3:
+ if (offset == slapstic.bank[0] || offset == slapstic.bank[1] ||
+ offset == slapstic.bank[2] || offset == slapstic.bank[3])
+ {
+ state = DISABLED;
+ current_bank = bit_bank;
+ }
+ break;
+
+ /* ADDITIVE1 state: look for add2 offset, or else fall back to ENABLED */
+ case ADDITIVE1:
+ if (MATCHES_MASK_VALUE(offset, slapstic.add2))
+ {
+ state = ADDITIVE2;
+ add_bank = current_bank;
+ }
+ else
+ {
+ state = ENABLED;
+ }
+ break;
+
+ /* ADDITIVE2 state: watch for twiddling and the escape mechanism */
+ case ADDITIVE2:
+
+ /* check for add 1 case -- can intermix */
+ if (MATCHES_MASK_VALUE(offset, slapstic.addplus1))
+ {
+ add_bank = (add_bank + 1) & 3;
+ }
+
+ /* check for add 2 case -- can intermix */
+ if (MATCHES_MASK_VALUE(offset, slapstic.addplus2))
+ {
+ add_bank = (add_bank + 2) & 3;
+ }
+
+ /* check for escape case -- can intermix with the above */
+ if (MATCHES_MASK_VALUE(offset, slapstic.add3))
+ {
+ state = ADDITIVE3;
+ }
+ break;
+
+ /* ADDITIVE3 state: waiting for a bank to seal the deal */
+ case ADDITIVE3:
+ if (offset == slapstic.bank[0] || offset == slapstic.bank[1] ||
+ offset == slapstic.bank[2] || offset == slapstic.bank[3])
+ {
+ state = DISABLED;
+ current_bank = add_bank;
+ }
+ break;
+ }
+ }
+
+ /* log this access */
+ slapstic_log(offset);
+
+ /* return the active bank */
+ return current_bank;
+}
+
+
+
+/*************************************
+ *
+ * Debugging
+ *
+ *************************************/
+
+#if LOG_SLAPSTIC
+static void slapstic_log(offs_t offset)
+{
+ static attotime last_time;
+
+ if (!slapsticlog)
+ slapsticlog = fopen("slapstic.log", "w");
+ if (slapsticlog)
+ {
+ attotime time = timer_get_time();
+
+ if (attotime_compare(attotime_sub(time, last_time), ATTOTIME_IN_SEC(1)) > 0)
+ fprintf(slapsticlog, "------------------------------------\n");
+ last_time = time;
+
+ fprintf(slapsticlog, "%06X: %04X B=%d ", activecpu_get_previouspc(), offset, current_bank);
+ switch (state)
+ {
+ case DISABLED:
+ fprintf(slapsticlog, "DISABLED\n");
+ break;
+ case ENABLED:
+ fprintf(slapsticlog, "ENABLED\n");
+ break;
+ case ALTERNATE1:
+ fprintf(slapsticlog, "ALTERNATE1\n");
+ break;
+ case ALTERNATE2:
+ fprintf(slapsticlog, "ALTERNATE2\n");
+ break;
+ case ALTERNATE3:
+ fprintf(slapsticlog, "ALTERNATE3\n");
+ break;
+ case BITWISE1:
+ fprintf(slapsticlog, "BITWISE1\n");
+ break;
+ case BITWISE2:
+ fprintf(slapsticlog, "BITWISE2\n");
+ break;
+ case BITWISE3:
+ fprintf(slapsticlog, "BITWISE3\n");
+ break;
+ case ADDITIVE1:
+ fprintf(slapsticlog, "ADDITIVE1\n");
+ break;
+ case ADDITIVE2:
+ fprintf(slapsticlog, "ADDITIVE2\n");
+ break;
+ case ADDITIVE3:
+ fprintf(slapsticlog, "ADDITIVE3\n");
+ break;
+ }
+ fflush(slapsticlog);
+ }
+}
+#endif