summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/asic65.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/asic65.c')
-rw-r--r--src/mame/machine/asic65.c750
1 files changed, 750 insertions, 0 deletions
diff --git a/src/mame/machine/asic65.c b/src/mame/machine/asic65.c
new file mode 100644
index 00000000000..a6f464ef29a
--- /dev/null
+++ b/src/mame/machine/asic65.c
@@ -0,0 +1,750 @@
+/*************************************
+ *
+ * Implementation of ASIC65
+ *
+ *************************************/
+
+#include "driver.h"
+#include "includes/atarig42.h"
+#include "cpu/tms32010/tms32010.h"
+#include "asic65.h"
+#include <math.h>
+
+
+#define LOG_ASIC 0
+
+
+/*************************************
+ *
+ * !$#@$ asic
+ *
+ *************************************/
+
+static UINT8 asic65_type;
+static int asic65_command;
+static UINT16 asic65_param[32];
+static UINT16 asic65_yorigin = 0x1800;
+static UINT8 asic65_param_index;
+static UINT8 asic65_result_index;
+static UINT8 asic65_reset_state;
+static UINT8 asic65_last_bank;
+
+/* ROM-based interface states */
+static UINT8 asic65_cpunum;
+static UINT8 asic65_tfull;
+static UINT8 asic65_68full;
+static UINT8 asic65_cmd;
+static UINT8 asic65_xflg;
+static UINT16 asic65_68data;
+static UINT16 asic65_tdata;
+
+static FILE * asic65_log;
+
+WRITE16_HANDLER( asic65_w );
+WRITE16_HANDLER( asic65_data_w );
+
+READ16_HANDLER( asic65_r );
+READ16_HANDLER( asic65_io_r );
+
+
+#define PARAM_WRITE 0
+#define COMMAND_WRITE 1
+#define DATA_READ 2
+
+#define OP_UNKNOWN 0
+#define OP_REFLECT 1
+#define OP_CHECKSUM 2
+#define OP_VERSION 3
+#define OP_RAMTEST 4
+#define OP_RESET 5
+#define OP_SIN 6
+#define OP_COS 7
+#define OP_ATAN 8
+#define OP_TMATRIXMULT 9
+#define OP_MATRIXMULT 10
+#define OP_TRANSFORM 11
+#define OP_YORIGIN 12
+#define OP_INITBANKS 13
+#define OP_SETBANK 14
+#define OP_VERIFYBANK 15
+
+#define MAX_COMMANDS 0x2b
+
+static const UINT8 command_map[3][MAX_COMMANDS] =
+{
+ {
+ /* standard version */
+ OP_UNKNOWN, OP_REFLECT, OP_CHECKSUM, OP_VERSION, /* 00-03 */
+ OP_RAMTEST, OP_UNKNOWN, OP_UNKNOWN, OP_RESET, /* 04-07 */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 08-0b */
+ OP_UNKNOWN, OP_UNKNOWN, OP_TMATRIXMULT, OP_UNKNOWN, /* 0c-0f */
+ OP_MATRIXMULT, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 10-13 */
+ OP_SIN, OP_COS, OP_YORIGIN, OP_TRANSFORM, /* 14-17 */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 18-1b */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 1c-1f */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 20-23 */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 24-27 */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN /* 28-2a */
+ },
+ {
+ /* Steel Talons version */
+ OP_UNKNOWN, OP_REFLECT, OP_CHECKSUM, OP_VERSION, /* 00-03 */
+ OP_RAMTEST, OP_UNKNOWN, OP_UNKNOWN, OP_RESET, /* 04-07 */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 08-0b */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 0c-0f */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 10-13 */
+ OP_TMATRIXMULT, OP_UNKNOWN, OP_MATRIXMULT, OP_UNKNOWN, /* 14-17 */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 18-1b */
+ OP_UNKNOWN, OP_UNKNOWN, OP_SIN, OP_COS, /* 1c-1f */
+ OP_ATAN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 20-23 */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 24-27 */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN /* 28-2a */
+ },
+ {
+ /* Guardians version */
+ OP_UNKNOWN, OP_REFLECT, OP_CHECKSUM, OP_VERSION, /* 00-03 */
+ OP_RAMTEST, OP_UNKNOWN, OP_UNKNOWN, OP_RESET, /* 04-07 */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 08-0b */
+ OP_UNKNOWN, OP_UNKNOWN, OP_INITBANKS, OP_SETBANK, /* 0c-0f */
+ OP_VERIFYBANK, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 10-13 */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 14-17 */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 18-1b */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 1c-1f */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 20-23 */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN, /* 24-27 */
+ OP_UNKNOWN, OP_UNKNOWN, OP_UNKNOWN /* 28-2a */
+ }
+};
+
+
+
+/*************************************
+ *
+ * Configure the chip
+ *
+ *************************************/
+
+void asic65_config(int asictype)
+{
+ asic65_type = asictype;
+ if (asic65_type == ASIC65_ROMBASED)
+ asic65_cpunum = mame_find_cpu_index(Machine, "asic65");
+}
+
+
+
+/*************************************
+ *
+ * Reset the chip
+ *
+ *************************************/
+
+void asic65_reset(int state)
+{
+ /* rom-based means reset and clear states */
+ if (asic65_type == ASIC65_ROMBASED)
+ cpunum_set_input_line(asic65_cpunum, INPUT_LINE_RESET, state ? ASSERT_LINE : CLEAR_LINE);
+
+ /* otherwise, do it manually */
+ else
+ {
+ cpunum_suspend(mame_find_cpu_index(Machine, "asic65"), SUSPEND_REASON_DISABLE, 1);
+
+ /* if reset is being signalled, clear everything */
+ if (state && !asic65_reset_state)
+ asic65_command = -1;
+
+ /* if reset is going high, latch the command */
+ else if (!state && asic65_reset_state)
+ {
+ if (asic65_command != -1)
+ asic65_data_w(1, asic65_command, 0);
+ }
+
+ /* update the state */
+ asic65_reset_state = state;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Handle writes to the chip
+ *
+ *************************************/
+
+static TIMER_CALLBACK( m68k_asic65_deferred_w )
+{
+ asic65_tfull = 1;
+ asic65_cmd = param >> 16;
+ asic65_tdata = param;
+ cpunum_set_input_line(asic65_cpunum, 0, ASSERT_LINE);
+}
+
+
+WRITE16_HANDLER( asic65_data_w )
+{
+ /* logging */
+#if LOG_ASIC
+ if (!asic65_log) asic65_log = fopen("asic65.log", "w");
+#endif
+
+ /* rom-based use a deferred write mechanism */
+ if (asic65_type == ASIC65_ROMBASED)
+ {
+ timer_call_after_resynch(data | (offset << 16), m68k_asic65_deferred_w);
+ cpu_boost_interleave(attotime_zero, ATTOTIME_IN_USEC(20));
+ return;
+ }
+
+ /* parameters go to offset 0 */
+ if (!(offset & 1))
+ {
+ if (asic65_log) fprintf(asic65_log, " W=%04X", data);
+
+ /* add to the parameter list, but don't overflow */
+ asic65_param[asic65_param_index++] = data;
+ if (asic65_param_index >= 32)
+ asic65_param_index = 32;
+ }
+
+ /* commands go to offset 2 */
+ else
+ {
+ int command = (data < MAX_COMMANDS) ? command_map[asic65_type][data] : OP_UNKNOWN;
+ if (asic65_log) fprintf(asic65_log, "\n(%06X)%c%04X:", activecpu_get_previouspc(), (command == OP_UNKNOWN) ? '*' : ' ', data);
+
+ /* set the command number and reset the parameter/result indices */
+ asic65_command = data;
+ asic65_result_index = asic65_param_index = 0;
+ }
+}
+
+
+READ16_HANDLER( asic65_r )
+{
+ int command = (asic65_command < MAX_COMMANDS) ? command_map[asic65_type][asic65_command] : OP_UNKNOWN;
+ INT64 element, result64 = 0;
+ UINT16 result = 0;
+
+ /* rom-based just returns latched data */
+ if (asic65_type == ASIC65_ROMBASED)
+ {
+ asic65_68full = 0;
+ cpu_boost_interleave(attotime_zero, ATTOTIME_IN_USEC(5));
+ return asic65_68data;
+ }
+
+ /* update results */
+ switch (command)
+ {
+ case OP_UNKNOWN: /* return bogus data */
+ popmessage("ASIC65: Unknown cmd %02X", asic65_command);
+ break;
+
+ case OP_REFLECT: /* reflect data */
+ if (asic65_param_index >= 1)
+ result = asic65_param[--asic65_param_index];
+ break;
+
+ case OP_CHECKSUM: /* compute checksum (should be XX27) */
+ result = 0x0027;
+ break;
+
+ case OP_VERSION: /* get version (returns 1.3) */
+ result = 0x0013;
+ break;
+
+ case OP_RAMTEST: /* internal RAM test (result should be 0) */
+ result = 0;
+ break;
+
+ case OP_RESET: /* reset */
+ asic65_result_index = asic65_param_index = 0;
+ break;
+
+ case OP_SIN: /* sin */
+ if (asic65_param_index >= 1)
+ result = (int)(16384. * sin(M_PI * (double)(INT16)asic65_param[0] / 32768.));
+ break;
+
+ case OP_COS: /* cos */
+ if (asic65_param_index >= 1)
+ result = (int)(16384. * cos(M_PI * (double)(INT16)asic65_param[0] / 32768.));
+ break;
+
+ case OP_ATAN: /* vector angle */
+ if (asic65_param_index >= 4)
+ {
+ INT32 xint = (INT32)((asic65_param[0] << 16) | asic65_param[1]);
+ INT32 yint = (INT32)((asic65_param[2] << 16) | asic65_param[3]);
+ double a = atan2((double)yint, (double)xint);
+ result = (INT16)(a * 32768. / M_PI);
+ }
+ break;
+
+ case OP_TMATRIXMULT: /* matrix multiply by transpose */
+ /* if this is wrong, the labels on the car selection screen */
+ /* in Race Drivin' will be off */
+ if (asic65_param_index >= 9+6)
+ {
+ INT32 v0 = (INT32)((asic65_param[9] << 16) | asic65_param[10]);
+ INT32 v1 = (INT32)((asic65_param[11] << 16) | asic65_param[12]);
+ INT32 v2 = (INT32)((asic65_param[13] << 16) | asic65_param[14]);
+
+ /* 2 results per element */
+ switch (asic65_result_index / 2)
+ {
+ case 0:
+ result64 = (INT64)v0 * (INT16)asic65_param[0] +
+ (INT64)v1 * (INT16)asic65_param[3] +
+ (INT64)v2 * (INT16)asic65_param[6];
+ break;
+
+ case 1:
+ result64 = (INT64)v0 * (INT16)asic65_param[1] +
+ (INT64)v1 * (INT16)asic65_param[4] +
+ (INT64)v2 * (INT16)asic65_param[7];
+ break;
+
+ case 2:
+ result64 = (INT64)v0 * (INT16)asic65_param[2] +
+ (INT64)v1 * (INT16)asic65_param[5] +
+ (INT64)v2 * (INT16)asic65_param[8];
+ break;
+ }
+
+ /* remove lower 14 bits and pass back either upper or lower words */
+ result64 >>= 14;
+ result = (asic65_result_index & 1) ? (result64 & 0xffff) : ((result64 >> 16) & 0xffff);
+ asic65_result_index++;
+ }
+ break;
+
+ case OP_MATRIXMULT: /* matrix multiply???? */
+ if (asic65_param_index >= 9+6)
+ {
+ INT32 v0 = (INT32)((asic65_param[9] << 16) | asic65_param[10]);
+ INT32 v1 = (INT32)((asic65_param[11] << 16) | asic65_param[12]);
+ INT32 v2 = (INT32)((asic65_param[13] << 16) | asic65_param[14]);
+
+ /* 2 results per element */
+ switch (asic65_result_index / 2)
+ {
+ case 0:
+ result64 = (INT64)v0 * (INT16)asic65_param[0] +
+ (INT64)v1 * (INT16)asic65_param[1] +
+ (INT64)v2 * (INT16)asic65_param[2];
+ break;
+
+ case 1:
+ result64 = (INT64)v0 * (INT16)asic65_param[3] +
+ (INT64)v1 * (INT16)asic65_param[4] +
+ (INT64)v2 * (INT16)asic65_param[5];
+ break;
+
+ case 2:
+ result64 = (INT64)v0 * (INT16)asic65_param[6] +
+ (INT64)v1 * (INT16)asic65_param[7] +
+ (INT64)v2 * (INT16)asic65_param[8];
+ break;
+ }
+
+ /* remove lower 14 bits and pass back either upper or lower words */
+ result64 >>= 14;
+ result = (asic65_result_index & 1) ? (result64 & 0xffff) : ((result64 >> 16) & 0xffff);
+ asic65_result_index++;
+ }
+ break;
+
+ case OP_YORIGIN:
+ if (asic65_param_index >= 1)
+ asic65_yorigin = asic65_param[asic65_param_index - 1];
+ break;
+
+ case OP_TRANSFORM: /* 3d transform */
+ if (asic65_param_index >= 2)
+ {
+ /* param 0 == 1/z */
+ /* param 1 == height */
+ /* param 2 == X */
+ /* param 3 == Y */
+ /* return 0 == scale factor for 1/z */
+ /* return 1 == transformed X */
+ /* return 2 == transformed Y, taking height into account */
+ element = (INT16)asic65_param[0];
+ if (asic65_param_index == 2)
+ {
+ result64 = (element * (INT16)asic65_param[1]) >> 8;
+ result64 -= 1;
+ if (result64 > 0x3fff) result64 = 0;
+ }
+ else if (asic65_param_index == 3)
+ {
+ result64 = (element * (INT16)asic65_param[2]) >> 15;
+ result64 += 0xa8;
+ }
+ else if (asic65_param_index == 4)
+ {
+ result64 = (INT16)((element * (INT16)asic65_param[3]) >> 10);
+ result64 = (INT16)asic65_yorigin - result64 - (result64 << 1);
+ }
+ result = result64 & 0xffff;
+ }
+ break;
+
+ case OP_INITBANKS: /* initialize banking */
+ asic65_last_bank = 0;
+ break;
+
+ case OP_SETBANK: /* set a bank */
+ {
+ static const UINT8 banklist[] =
+ {
+ 1,4,0,4,4,3,4,2, 4,4,4,4,4,4,4,4,
+ 3,3,4,4,1,1,0,0, 4,4,4,4,2,2,4,4,
+ 4,4
+ };
+ static const UINT16 bankaddr[][8] =
+ {
+ { 0x77c0,0x77ce,0x77c2,0x77cc,0x77c4,0x77ca,0x77c6,0x77c8 },
+ { 0x77d0,0x77de,0x77d2,0x77dc,0x77d4,0x77da,0x77d6,0x77d8 },
+ { 0x77e0,0x77ee,0x77e2,0x77ec,0x77e4,0x77ea,0x77e6,0x77e8 },
+ { 0x77f0,0x77fe,0x77f2,0x77fc,0x77f4,0x77fa,0x77f6,0x77f8 },
+ { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 },
+ };
+ if (asic65_param_index >= 1)
+ {
+ if (asic65_param_index < sizeof(banklist) && banklist[asic65_param[0]] < 4)
+ asic65_last_bank = banklist[asic65_param[0]];
+ result = bankaddr[asic65_last_bank][(asic65_result_index < 8) ? asic65_result_index : 7];
+ asic65_result_index++;
+ }
+ break;
+ }
+
+ case OP_VERIFYBANK: /* verify a bank */
+ {
+ static const UINT16 bankverify[] =
+ {
+ 0x0eb2,0x1000,0x171b,0x3d28
+ };
+ result = bankverify[asic65_last_bank];
+ break;
+ }
+ }
+
+#if LOG_ASIC
+ if (!asic65_log) asic65_log = fopen("asic65.log", "w");
+#endif
+ if (asic65_log) fprintf(asic65_log, " (R=%04X)", result);
+
+ return result;
+}
+
+
+READ16_HANDLER( asic65_io_r )
+{
+ if (asic65_type == ASIC65_ROMBASED)
+ {
+ /* bit 15 = TFULL */
+ /* bit 14 = 68FULL */
+ /* bit 13 = XFLG */
+ /* bit 12 = controlled by jumper */
+ cpu_boost_interleave(attotime_zero, ATTOTIME_IN_USEC(5));
+ return (asic65_tfull << 15) | (asic65_68full << 14) | (asic65_xflg << 13) | 0x0000;
+ }
+ else
+ {
+ /* indicate that we always are ready to accept data and always ready to send */
+ return 0x4000;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Read/write handlers for TMS32015
+ *
+ *************************************/
+
+static WRITE16_HANDLER( asic65_68k_w )
+{
+ asic65_68full = 1;
+ asic65_68data = data;
+}
+
+
+static READ16_HANDLER( asic65_68k_r )
+{
+ asic65_tfull = 0;
+ cpunum_set_input_line(asic65_cpunum, 0, CLEAR_LINE);
+ return asic65_tdata;
+}
+
+
+static WRITE16_HANDLER( asic65_stat_w )
+{
+ asic65_xflg = data & 1;
+}
+
+
+static READ16_HANDLER( asic65_stat_r )
+{
+ /* bit 15 = 68FULL */
+ /* bit 14 = TFULL */
+ /* bit 13 = CMD */
+ /* bit 12 = controlled by jumper (0 = test?) */
+ return (asic65_68full << 15) | (asic65_tfull << 14) | (asic65_cmd << 13) | 0x1000;
+}
+
+
+static READ16_HANDLER( asci65_get_bio )
+{
+ if (!asic65_tfull)
+ cpu_spinuntil_int();
+ return asic65_tfull ? CLEAR_LINE : ASSERT_LINE;
+}
+
+
+
+/*************************************
+ *
+ * Address maps for TMS32015
+ *
+ *************************************/
+
+static ADDRESS_MAP_START( asic65_program_map, ADDRESS_SPACE_PROGRAM, 16 )
+ ADDRESS_MAP_FLAGS( AMEF_UNMAP(1) )
+ AM_RANGE(0x000, 0xfff) AM_ROM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( asic65_io_map, ADDRESS_SPACE_IO, 16 )
+ AM_RANGE(0, 0) AM_MIRROR(6) AM_READWRITE(asic65_68k_r, asic65_68k_w)
+ AM_RANGE(1, 1) AM_MIRROR(6) AM_READWRITE(asic65_stat_r, asic65_stat_w)
+ AM_RANGE(TMS32010_BIO, TMS32010_BIO) AM_READ(asci65_get_bio)
+ADDRESS_MAP_END
+
+
+
+/*************************************
+ *
+ * Machine driver for ROM-based
+ *
+ *************************************/
+
+MACHINE_DRIVER_START( asic65 )
+
+ /* ASIC65 */
+ MDRV_CPU_ADD_TAG("asic65", TMS32010, 20000000/TMS32010_CLOCK_DIVIDER)
+ MDRV_CPU_PROGRAM_MAP(asic65_program_map,0)
+ MDRV_CPU_IO_MAP(asic65_io_map,0)
+MACHINE_DRIVER_END
+
+
+
+/***********************************************************************
+
+ Information about various versions:
+
+ Notation:
+ C = command write
+ W = write
+ R = read
+ 7 = wait for bit 7
+ 6 = wait for bit 6
+
+ Guardians of the Hood:
+ Version = 0040
+ Checksum = ????
+
+ Command $08: C7
+ Command $09: C7W6R
+ Command $0a: C7
+ Command $0b: C7W7W7W7W7WW7W7W7W
+ Command $0c: C7W7W7W7W7W7W
+ Command $0d: C7W7W
+ Command $0e: C7W7W7W7W7WW7W7W7WWWWWWW6R6R6R6R6R6R
+ Command $0f: C7W7W7W7W7W7W6R6R6R6R6R6R
+ Command $10: C7W7W7W7W7WW7W7W7WWWWWWW6R6R6R6R6R6R
+ Command $11: C7W7W7W7W7W7W6R6R6R6R6R6R
+ Command $12: C7W7W7W7W7WW7W7W7W6R6R6R6R6R6R6R6R6R
+ Command $13: C7W7W7W7W7WW7W7W7W
+ Command $14: C7W6R
+ Command $15: C7W6R
+ Command $16: C7W6R6R
+ Command $17: C7W
+ Command $18: C76R6R6R6R6R6R6R6R6R
+ Command $19: C7
+ Command $1a: C76R6R6R6R6R6R6R6R6R
+ Command $1b: C7
+ Command $1c: C76R6R6R6R6R6R6R6R6R
+ Command $1d: C7
+ Command $1e: C76R6R6R6R6R6R6R6R6R
+ Command $1f: C7
+ Command $20: C76R6R6R6R6R6R6R6R6R
+ Command $21: C7
+ Command $22: C76R6R6R6R6R6R6R6R6R
+ Command $23: C7
+ Command $24: C7
+
+ Command $0e: C76RRRRRRRRR
+ Command $0f: C7W6RRRRRRRR
+ Command $16: C7W
+ Command $17: C7W7W7W7W6R6R6R
+
+ Road Riot 4WD:
+ Version = ????
+ Checksum = ????
+
+ Command $08: C7
+ Command $09: C7W6R
+ Command $0a: C7
+ Command $0b: C7W7WWWWWWWW
+ Command $0c: C7W7WWWWW
+ Command $0d: C7W7W
+ Command $0e: C7W7WWWWWWWWWWWWWW6RRRRRR
+ Command $0f: C7W7WWWWW6RRRRRR
+ Command $10: C7W7WWWWWWWWWWWWWW6RRRRRR
+ Command $11: C7W7WWWWW6RRRRRR
+ Command $12: C7W7WWWWWWWW6RRRRRRRRR
+ Command $13: C7W7WWWWWWWW
+ Command $14: C7W6R
+ Command $15: C7W6R
+ Command $16: C7W6RR
+ Command $17: C7W
+ Command $18: C76RRRRRRRRR
+ Command $19: C7
+ Command $1a: C76RRRRRRRRR
+ Command $1b: C7
+ Command $1c: C76RRRRRRRRR
+ Command $1d: C7
+ Command $1e: C76RRRRRRRRR
+ Command $1f: C7
+ Command $20: C76RRRRRRRRR
+ Command $21: C7
+ Command $22: C76RRRRRRRRR
+ Command $23: C7
+ Command $24: C7
+
+ Command $16: C7W
+ Command $17: C7W7WWW6RRR
+ Command $17: C7WRWRWR
+
+ Race Drivin':
+ Version = ????
+ Checksum = ????
+
+ Command $08: C7
+ Command $09: C7W6R
+ Command $0a: C7
+ Command $0b: C7W7WWWWWWWW
+ Command $0c: C7W7WWWWW
+ Command $0d: C7W7W
+ Command $0e: C7W7WWWWWWWWWWWWWW6RRRRRR
+ Command $0f: C7W7WWWWW6RRRRRR
+ Command $10: C7W7WWWWWWWWWWWWWW6RRRRRR
+ Command $11: C7W7WWWWW6RRRRRR
+ Command $12: C7W7WWWWWWWW6RRRRRRRRR
+ Command $13: C7W7WWWWWWWW
+ Command $14: C7W6R
+ Command $15: C7W6R
+ Command $16: C7W6RR
+ Command $17: C7W
+ Command $18: C76RRRRRRRRR
+ Command $19: C7
+ Command $1a: C76RRRRRRRRR
+ Command $1b: C7
+ Command $1c: C76RRRRRRRRR
+ Command $1d: C7
+ Command $1e: C76RRRRRRRRR
+ Command $1f: C7
+ Command $20: C76RRRRRRRRR
+ Command $21: C7
+ Command $22: C76RRRRRRRRR
+ Command $23: C7
+ Command $24: C7
+
+ Command $0e: C7W7WWWWWWWWWWWWWW6RRRRRR
+ Command $14: C7W6R
+ Command $15: C7W6R
+
+ Steel Talons:
+ Version = ????
+ Checksum = ????
+
+ Command $08: C7
+ Command $09: C7W6R
+ Command $0a: C7
+ Command $0b: C7W7WWWWWWWW
+ Command $0c: C7W7WWWWW
+ Command $0d: C7W7W
+ Command $14: C7W7WWWWWWWWWWWWWW6RRRRRR
+ Command $15: C7W7WWWWW6RRRRRR
+ Command $16: C7W7WWWWWWWWWWWWWW6RRRRRR
+ Command $17: C7W7WWWWW6RRRRRR
+ Command $12: C7W7WWWWWWWW6RRRRRRRRR
+ Command $13: C7W7WWWWWWWW
+ Command $1e: C7W6R
+ Command $1f: C7W6R
+ Command $16: C7W6RR
+ Command $17: C7W
+ Command $20: C7W7WWW6R
+ Command $18: C76RRRRRRRRR
+ Command $19: C7
+ Command $1a: C76RRRRRRRRR
+ Command $1b: C7
+ Command $1c: C76RRRRRRRRR
+ Command $1d: C7
+ Command $1e: C76RRRRRRRRR
+ Command $1f: C7
+ Command $20: C76RRRRRRRRR
+ Command $21: C7
+ Command $22: C76RRRRRRRRR
+ Command $23: C7
+ Command $24: C7
+
+ Hard Drivin's Airborne:
+ Version = ????
+ Checksum = ????
+
+ Command $0e: C7W7WWWWWWWWWWWWWW6RRRRRR
+ Command $14: C7W6R
+
+ Command $08: C7
+ Command $09: C7W6R
+ Command $0a: C7
+ Command $0b: C7W7WWWWWWWW
+ Command $0c: C7W7WWWWW
+ Command $0d: C7W7W
+ Command $0e: C7W7WWWWWWWWWWWWWW6RRRRRR
+ Command $0f: C7W7WWWWW6RRRRRR
+ Command $10: C7W7WWWWWWWWWWWWWW6RRRRRR
+ Command $11: C7W7WWWWW6RRRRRR
+ Command $12: C7W7WWWWWWWW6RRRRRRRRR
+ Command $13: C7W7WWWWWWWW
+ Command $14: C7W6R
+ Command $15: C7W6R
+ Command $16: C7W6RR
+ Command $17: C7W
+ Command $18: C76RRRRRRRRR
+ Command $19: C7
+ Command $1a: C76RRRRRRRRR
+ Command $1b: C7
+ Command $1c: C76RRRRRRRRR
+ Command $1d: C7
+ Command $1e: C76RRRRRRRRR
+ Command $1f: C7
+ Command $20: C76RRRRRRRRR
+ Command $21: C7
+ Command $22: C76RRRRRRRRR
+ Command $23: C7
+ Command $24: C7
+ Command $26: C7W
+ Command $27: C7W7WWWWW
+ Command $28: C7
+ Command $2a: C76RRRRRRRRR
+
+***********************************************************************/