summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/namcoio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/namcoio.c')
-rw-r--r--src/mame/machine/namcoio.c1081
1 files changed, 1081 insertions, 0 deletions
diff --git a/src/mame/machine/namcoio.c b/src/mame/machine/namcoio.c
new file mode 100644
index 00000000000..84c601e15c8
--- /dev/null
+++ b/src/mame/machine/namcoio.c
@@ -0,0 +1,1081 @@
+/***************************************************************************
+
+The following Namco custom chips are all instances of the same 4-bit MCU,
+the Fujitsu MB8843 (42-pin DIP package) and MB8842/MB8844 (28-pin DIP),
+differently programmed.
+
+chip MCU pins function
+---- ------ ---- --------
+50XX MB8842 28 player score handling (protection)
+51XX MB8843 42 I/O (coin management built-in)
+52XX MB8843 42 sample playback
+53XX MB8843 42 I/O (steering wheel support)
+54XX MB8844 28 explosion (noise) generator
+56XX 42 I/O (coin management built-in)
+58XX 42 I/O (coin management built-in)
+62XX 28 I/O and explosion (noise) generator
+
+06XX interface:
+---------------
+Galaga 51XX ---- ---- 54XX
+Bosconian (CPU board) 51XX ---- 50XX 54XX
+Bosconian (Video board) 50XX 52XX ---- ----
+Xevious 51XX ---- 50XX 54XX
+Dig Dug 51XX 53XX ---- ----
+Pole Position / PP II 51XX 53XX 52XX 54XX
+
+16XX interface:
+---------------
+Super Pac Man 56XX 56XX ---- ----
+Pac & Pal 56XX 59XX ---- ----
+Mappy 58XX 58XX ---- ----
+Phozon 58XX 56XX ---- ----
+The Tower of Druaga 58XX 56XX ---- ----
+Grobda 58XX 56XX ---- ----
+Dig Dug II 58XX 56XX ---- ----
+Motos 56XX 56XX ---- ----
+Gaplus 56XX 58XX 62XX ----
+Gaplus (alt.) 58XX 56XX 62XX ----
+Libble Rabble 58XX 56XX 56XX ----
+Toy Pop 58XX 56XX 56XX ----
+
+
+Pinouts:
+
+ MB8843 MB8842/MB8844
+ +------+ +------+
+ EXTAL|1 42|Vcc EXTAL|1 28|Vcc
+ XTAL|2 41|K3 XTAL|2 27|K3
+ /RESET|3 40|K2 /RESET|3 26|K2
+ /IRQ|4 39|K1 O0|4 25|K1
+ SO|5 38|K0 O1|5 24|K0
+ SI|6 37|R15 O2|6 23|R10 /IRQ
+/SC /TO|7 36|R14 O3|7 22|R9 /TC
+ /TC|8 35|R13 O4|8 21|R8
+ P0|9 34|R12 O5|9 20|R7
+ P1|10 33|R11 O6|10 19|R6
+ P2|11 32|R10 O7|11 18|R5
+ P3|12 31|R9 R0|12 17|R4
+ O0|13 30|R8 R1|13 16|R3
+ O1|14 29|R7 GND|14 15|R2
+ O2|15 28|R6 +------+
+ O3|16 27|R5
+ O4|17 26|R4
+ O5|18 25|R3
+ O6|19 24|R2
+ O7|20 23|R1
+ GND|21 22|R0
+ +------+
+
+
+ O O R R R K
+50XX O O I I I
+54XX O O I O I
+62XX O O IO O I
+
+ P O O R R R R K
+51XX O O O I I I I I
+52XX O O O I I O O I
+53XX O? O O I I I I I
+56XX O O O I I I IO I
+58XX O O O I I I IO I
+59XX O O O I I I IO I
+
+
+For the 52XX, see sound/namco52.c
+
+For the 54XX, see audio/namco54.c
+
+
+Namco custom I/O chips 56XX, 58XX, 59XX
+
+These chips work together with a 16XX, that interfaces them with the buffer
+RAM. Each chip uses 16 nibbles of memory; the 16XX supports up to 4 chips,
+but most games use only 2.
+
+The 56XX, 58XX and 59XX are pin-to-pin compatible, but not functionally equivalent:
+they provide the same functions, but the command codes and memory addresses
+are different, so they cannot be exchanged.
+
+The devices have 42 pins. There are 16 input lines and 8 output lines to be
+used for I/O.
+
+
+pin description
+--- -----------
+1 clock (Mappy, Super Pac-Man)
+2 clock (Gaplus; equivalent to the above?)
+3 reset
+4 irq
+5-6 (to/from 16XX) (this is probably a normal I/O port used to synchronize with the 16XX)
+7-8 ?
+9-12 address to r/w from RAM; 12 also goes to the 16XX and acts as r/w line, so
+ the chip can only read from addresses 0-7 and only write to addresses 8-F
+ (this is probably a normal I/O port used for that purpose)
+13-16 out port A
+17-20 out port B
+21 GND
+22-25 in port B
+26-29 in port C
+30-33 in port D
+34-37 (to 16XX) probably data to r/w from RAM
+ (this is probably a normal I/O port used for that purpose)
+38-41 in port A
+42 Vcc
+
+TODO:
+- It's likely that the 56XX and 58XX chips, when in "coin mode", also internally
+ handle outputs for start lamps, coin counters and coin lockout, like the 51XX.
+ Such lines are NOT present in the Mappy and Super Pacman schematics, so they
+ were probably not used for those games, but they might have been used in
+ others (most likely Gaplus).
+
+***************************************************************************/
+
+#include "driver.h"
+#include "machine/namcoio.h"
+#include "machine/namco50.h"
+#include "sound/namco52.h"
+#include "audio/namco54.h"
+
+
+#define VERBOSE 0
+
+struct namcoio
+{
+ INT32 type;
+ read8_handler in[4];
+ write8_handler out[2];
+ INT32 reset;
+ INT32 lastcoins,lastbuttons;
+ INT32 credits;
+ INT32 coins[2];
+ INT32 coins_per_cred[2];
+ INT32 creds_per_coin[2];
+ INT32 in_count;
+ INT32 mode,coincred_mode,remap_joy; // for 51XX
+};
+
+static struct namcoio io[MAX_NAMCOIO];
+static INT32 nmi_cpu[MAX_06XX];
+static emu_timer *nmi_timer[MAX_06XX];
+
+static READ8_HANDLER( nop_r ) { return 0x0f; }
+static WRITE8_HANDLER( nop_w ) { }
+
+#define READ_PORT(n) (io[chip].in[n](0) & 0x0f)
+#define WRITE_PORT(n,d) io[chip].out[n](0,(d) & 0x0f)
+
+
+
+/*
+51XX
+
+commands:
+00: nop
+01 + 4 arguments: set coinage (xevious, possibly because of a bug, is different)
+02: go in "credit" mode and enable start buttons
+03: disable joystick remapping
+04: enable joystick remapping
+05: go in "switch" mode
+06: nop
+07: nop
+*/
+
+static void namcoio_51XX_write(int chip,int data)
+{
+ data &= 0x07;
+
+#if VERBOSE
+ logerror("%04x: custom 51XX write %02x\n",activecpu_get_pc(),data);
+#endif
+
+ if (io[chip].coincred_mode)
+ {
+ switch (io[chip].coincred_mode--)
+ {
+ case 4: io[chip].coins_per_cred[0] = data; break;
+ case 3: io[chip].creds_per_coin[0] = data; break;
+ case 2: io[chip].coins_per_cred[1] = data; break;
+ case 1: io[chip].creds_per_coin[1] = data; break;
+ }
+ }
+ else
+ {
+ switch (data)
+ {
+ case 0: // nop
+ break;
+
+ case 1: // set coinage
+ io[chip].coincred_mode = 4;
+ /* this is a good time to reset the credits counter */
+ io[chip].credits = 0;
+
+ {
+ /* kludge for a possible bug in Xevious */
+ static const game_driver *namcoio_51XX_driver = NULL;
+ static int namcoio_51XX_kludge = 0;
+
+ /* Only compute namcoio_51XX_kludge when gamedrv changes */
+ if (namcoio_51XX_driver != Machine->gamedrv)
+ {
+ namcoio_51XX_driver = Machine->gamedrv;
+ if (strcmp(namcoio_51XX_driver->name, "xevious") == 0 ||
+ strcmp(namcoio_51XX_driver->parent, "xevious") == 0)
+ namcoio_51XX_kludge = 1;
+ else
+ namcoio_51XX_kludge = 0;
+ }
+
+ if (namcoio_51XX_kludge)
+ {
+ io[chip].coincred_mode = 6;
+ io[chip].remap_joy = 1;
+ }
+ }
+ break;
+
+ case 2: // go in "credits" mode and enable start buttons
+ io[chip].mode = 1;
+ io[chip].in_count = 0;
+ break;
+
+ case 3: // disable joystick remapping
+ io[chip].remap_joy = 0;
+ break;
+
+ case 4: // enable joystick remapping
+ io[chip].remap_joy = 1;
+ break;
+
+ case 5: // go in "switch" mode
+ io[chip].mode = 0;
+ io[chip].in_count = 0;
+ break;
+
+ default:
+ logerror("unknown 51XX command %02x\n",data);
+ break;
+ }
+ }
+}
+
+
+/* joystick input mapping
+
+ The joystick is parsed and a number corresponding to the direction is returned,
+ according to the following table:
+
+ 0
+ 7 1
+ 6 8 2
+ 5 3
+ 4
+
+ The values for directions impossible to obtain on a joystick have not been
+ verified on Namco original hardware, but they are the same in all the bootlegs,
+ so we can assume they are right.
+*/
+static int joy_map[16] =
+/* LDRU, LDR, LDU, LD, LRU, LR, LU, L, DRU, DR, DU, D, RU, R, U, center */
+{ 0xf, 0xe, 0xd, 0x5, 0xc, 0x9, 0x7, 0x6, 0xb, 0x3, 0xa, 0x4, 0x1, 0x2, 0x0, 0x8 };
+
+
+static UINT8 namcoio_51XX_read(int chip)
+{
+#if VERBOSE
+ logerror("%04x: custom 51XX read\n",activecpu_get_pc());
+#endif
+
+ if (io[chip].mode == 0) /* switch mode */
+ {
+ switch ((io[chip].in_count++) % 3)
+ {
+ default:
+ case 0: return READ_PORT(0) | (READ_PORT(1) << 4);
+ case 1: return READ_PORT(2) | (READ_PORT(3) << 4);
+ case 2: return 0; // nothing?
+ }
+ }
+ else /* credits mode */
+ {
+ switch ((io[chip].in_count++) % 3)
+ {
+ default:
+ case 0: // number of credits in BCD format
+ {
+ int in,toggle;
+
+ in = ~(READ_PORT(0) | (READ_PORT(1) << 4));
+ toggle = in ^ io[chip].lastcoins;
+ io[chip].lastcoins = in;
+
+ if (io[chip].coins_per_cred[0] > 0)
+ {
+ if (io[chip].credits >= 99)
+ {
+ WRITE_PORT(1,1); // coin lockout
+ }
+ else
+ {
+ WRITE_PORT(1,0); // coin lockout
+ /* check if the user inserted a coin */
+ if (toggle & in & 0x10)
+ {
+ io[chip].coins[0]++;
+ WRITE_PORT(0,0x04); // coin counter
+ WRITE_PORT(0,0x0c);
+ if (io[chip].coins[0] >= io[chip].coins_per_cred[0])
+ {
+ io[chip].credits += io[chip].creds_per_coin[0];
+ io[chip].coins[0] -= io[chip].coins_per_cred[0];
+ }
+ }
+ if (toggle & in & 0x20)
+ {
+ io[chip].coins[1]++;
+ WRITE_PORT(0,0x08); // coin counter
+ WRITE_PORT(0,0x0c);
+ if (io[chip].coins[1] >= io[chip].coins_per_cred[1])
+ {
+ io[chip].credits += io[chip].creds_per_coin[1];
+ io[chip].coins[1] -= io[chip].coins_per_cred[1];
+ }
+ }
+ if (toggle & in & 0x40)
+ {
+ io[chip].credits++;
+ }
+ }
+ }
+ else io[chip].credits = 100; // free play
+
+ if (io[chip].mode == 1)
+ {
+ int on = (cpu_getcurrentframe() & 0x10) >> 4;
+
+ if (io[chip].credits >= 2)
+ WRITE_PORT(0,0x0c | 3*on); // lamps
+ else if (io[chip].credits >= 1)
+ WRITE_PORT(0,0x0c | 2*on); // lamps
+ else
+ WRITE_PORT(0,0x0c); // lamps off
+
+ /* check for 1 player start button */
+ if (toggle & in & 0x04)
+ {
+ if (io[chip].credits >= 1)
+ {
+ io[chip].credits--;
+ io[chip].mode = 2;
+ WRITE_PORT(0,0x0c); // lamps off
+ }
+ }
+ /* check for 2 players start button */
+ else if (toggle & in & 0x08)
+ {
+ if (io[chip].credits >= 2)
+ {
+ io[chip].credits -= 2;
+ io[chip].mode = 2;
+ WRITE_PORT(0,0x0c); // lamps off
+ }
+ }
+ }
+ }
+
+ if (~readinputport(0) & 0x80) /* check test mode switch */
+ return 0xbb;
+
+ return (io[chip].credits / 10) * 16 + io[chip].credits % 10;
+
+ case 1:
+ {
+ int joy = READ_PORT(2) & 0x0f;
+ int in,toggle;
+
+ in = ~READ_PORT(0);
+ toggle = in ^ io[chip].lastbuttons;
+ io[chip].lastbuttons = (io[chip].lastbuttons & 2) | (in & 1);
+
+ /* remap joystick */
+ if (io[chip].remap_joy) joy = joy_map[joy];
+
+ /* fire */
+ joy |= ((toggle & in & 0x01)^1) << 4;
+ joy |= ((in & 0x01)^1) << 5;
+
+ return joy;
+ }
+
+ case 2:
+ {
+ int joy = READ_PORT(3) & 0x0f;
+ int in,toggle;
+
+ in = ~READ_PORT(0);
+ toggle = in ^ io[chip].lastbuttons;
+ io[chip].lastbuttons = (io[chip].lastbuttons & 1) | (in & 2);
+
+ /* remap joystick */
+ if (io[chip].remap_joy) joy = joy_map[joy];
+
+ /* fire */
+ joy |= ((toggle & in & 0x02)^2) << 3;
+ joy |= ((in & 0x02)^2) << 4;
+
+ return joy;
+ }
+ }
+ }
+}
+
+
+/***************************************************************************/
+
+
+static UINT8 namcoio_ram[MAX_NAMCOIO * 16];
+
+#define IORAM_READ(offset) (namcoio_ram[chip * 0x10 + (offset)] & 0x0f)
+#define IORAM_WRITE(offset,data) {namcoio_ram[chip * 0x10 + (offset)] = (data) & 0x0f;}
+
+
+static void handle_coins(int chip,int swap)
+{
+ int val,toggled;
+ int credit_add = 0;
+ int credit_sub = 0;
+ int button;
+
+//popmessage("%x %x %x %x %x %x %x %x",IORAM_READ(8),IORAM_READ(9),IORAM_READ(10),IORAM_READ(11),IORAM_READ(12),IORAM_READ(13),IORAM_READ(14),IORAM_READ(15));
+
+ val = ~READ_PORT(0); // pins 38-41
+ toggled = val ^ io[chip].lastcoins;
+ io[chip].lastcoins = val;
+
+ /* check coin insertion */
+ if (val & toggled & 0x01)
+ {
+ io[chip].coins[0]++;
+ if (io[chip].coins[0] >= (io[chip].coins_per_cred[0] & 7))
+ {
+ credit_add = io[chip].creds_per_coin[0] - (io[chip].coins_per_cred[0] >> 3);
+ io[chip].coins[0] -= io[chip].coins_per_cred[0] & 7;
+ }
+ else if (io[chip].coins_per_cred[0] & 8)
+ credit_add = 1;
+ }
+ if (val & toggled & 0x02)
+ {
+ io[chip].coins[1]++;
+ if (io[chip].coins[1] >= (io[chip].coins_per_cred[1] & 7))
+ {
+ credit_add = io[chip].creds_per_coin[1] - (io[chip].coins_per_cred[1] >> 3);
+ io[chip].coins[1] -= io[chip].coins_per_cred[1] & 7;
+ }
+ else if (io[chip].coins_per_cred[1] & 8)
+ credit_add = 1;
+ }
+ if (val & toggled & 0x08)
+ {
+ credit_add = 1;
+ }
+
+ val = ~READ_PORT(3); // pins 30-33
+ toggled = val ^ io[chip].lastbuttons;
+ io[chip].lastbuttons = val;
+
+ /* check start buttons, only if the game allows */
+ if (IORAM_READ(9) == 0)
+ // the other argument is IORAM_READ(10) = 1, meaning unknown
+ {
+ if (val & toggled & 0x04)
+ {
+ if (io[chip].credits >= 1) credit_sub = 1;
+ }
+ else if (val & toggled & 0x08)
+ {
+ if (io[chip].credits >= 2) credit_sub = 2;
+ }
+ }
+
+ io[chip].credits += credit_add - credit_sub;
+
+ IORAM_WRITE(0 ^ swap, io[chip].credits / 10); // BCD credits
+ IORAM_WRITE(1 ^ swap, io[chip].credits % 10); // BCD credits
+ IORAM_WRITE(2 ^ swap, credit_add); // credit increment (coin inputs)
+ IORAM_WRITE(3 ^ swap, credit_sub); // credit decrement (start buttons)
+ IORAM_WRITE(4, ~READ_PORT(1)); // pins 22-25
+ button = ((val & 0x05) << 1) | (val & toggled & 0x05);
+ IORAM_WRITE(5, button); // pins 30 & 32 normal and impulse
+ IORAM_WRITE(6, ~READ_PORT(2)); // pins 26-29
+ button = (val & 0x0a) | ((val & toggled & 0x0a) >> 1);
+ IORAM_WRITE(7, button); // pins 31 & 33 normal and impulse
+}
+
+
+
+static void namco_customio_56XX_run(int chip)
+{
+#if VERBOSE
+ logerror("execute 56XX %d mode %d\n",chip,IORAM_READ(8));
+#endif
+
+ switch (IORAM_READ(8))
+ {
+ case 0: // nop?
+ break;
+
+ case 1: // read switch inputs
+ IORAM_WRITE(0, ~READ_PORT(0)); // pins 38-41
+ IORAM_WRITE(1, ~READ_PORT(1)); // pins 22-25
+ IORAM_WRITE(2, ~READ_PORT(2)); // pins 26-29
+ IORAM_WRITE(3, ~READ_PORT(3)); // pins 30-33
+
+//popmessage("%x %x %x %x %x %x %x %x",IORAM_READ(8),IORAM_READ(9),IORAM_READ(10),IORAM_READ(11),IORAM_READ(12),IORAM_READ(13),IORAM_READ(14),IORAM_READ(15));
+
+ WRITE_PORT(0,IORAM_READ(9)); // output to pins 13-16 (motos, pacnpal, gaplus)
+ WRITE_PORT(1,IORAM_READ(10)); // output to pins 17-20 (gaplus)
+ break;
+
+ case 2: // initialize coinage settings
+ io[chip].coins_per_cred[0] = IORAM_READ(9);
+ io[chip].creds_per_coin[0] = IORAM_READ(10);
+ io[chip].coins_per_cred[1] = IORAM_READ(11);
+ io[chip].creds_per_coin[1] = IORAM_READ(12);
+ // IORAM_READ(13) = 1; meaning unknown - possibly a 3rd coin input? (there's a IPT_UNUSED bit in port A)
+ // IORAM_READ(14) = 1; meaning unknown - possibly a 3rd coin input? (there's a IPT_UNUSED bit in port A)
+ // IORAM_READ(15) = 0; meaning unknown
+ break;
+
+ case 4: // druaga, digdug chip #1: read dip switches and inputs
+ // superpac chip #0: process coin and start inputs, read switch inputs
+ handle_coins(chip,0);
+ break;
+
+ case 7: // bootup check (liblrabl only)
+ {
+ // liblrabl chip #1: 9-15 = f 1 2 3 4 0 0, expects 2 = e
+ // liblrabl chip #2: 9-15 = 0 1 4 5 5 0 0, expects 7 = 6
+ IORAM_WRITE(2,0xe);
+ IORAM_WRITE(7,0x6);
+ }
+ break;
+
+ case 8: // bootup check
+ {
+ int i,sum;
+
+ // superpac: 9-15 = f f f f f f f, expects 0-1 = 6 9. 0x69 = f+f+f+f+f+f+f.
+ // motos: 9-15 = f f f f f f f, expects 0-1 = 6 9. 0x69 = f+f+f+f+f+f+f.
+ // phozon: 9-15 = 1 2 3 4 5 6 7, expects 0-1 = 1 c. 0x1c = 1+2+3+4+5+6+7
+ sum = 0;
+ for (i = 9;i < 16;i++)
+ sum += IORAM_READ(i);
+ IORAM_WRITE(0,sum >> 4);
+ IORAM_WRITE(1,sum & 0xf);
+ }
+ break;
+
+ case 9: // read dip switches and inputs
+ WRITE_PORT(0,0); // set pin 13 = 0
+ IORAM_WRITE(0, ~READ_PORT(0)); // pins 38-41, pin 13 = 0
+ IORAM_WRITE(2, ~READ_PORT(1)); // pins 22-25, pin 13 = 0
+ IORAM_WRITE(4, ~READ_PORT(2)); // pins 26-29, pin 13 = 0
+ IORAM_WRITE(6, ~READ_PORT(3)); // pins 30-33, pin 13 = 0
+ WRITE_PORT(0,1); // set pin 13 = 1
+ IORAM_WRITE(1, ~READ_PORT(0)); // pins 38-41, pin 13 = 1
+ IORAM_WRITE(3, ~READ_PORT(1)); // pins 22-25, pin 13 = 1
+ IORAM_WRITE(5, ~READ_PORT(2)); // pins 26-29, pin 13 = 1
+ IORAM_WRITE(7, ~READ_PORT(3)); // pins 30-33, pin 13 = 1
+ break;
+
+ default:
+ logerror("Namco I/O %d: unknown I/O mode %d\n",chip,IORAM_READ(8));
+ }
+}
+
+
+
+static void namco_customio_59XX_run(int chip)
+{
+#if VERBOSE
+ logerror("execute 59XX %d mode %d\n",chip,IORAM_READ(8));
+#endif
+
+ switch (IORAM_READ(8))
+ {
+ case 0: // nop?
+ break;
+
+ case 3: // pacnpal chip #1: read dip switches and inputs
+ IORAM_WRITE(4, ~READ_PORT(0)); // pins 38-41, pin 13 = 0 ?
+ IORAM_WRITE(5, ~READ_PORT(2)); // pins 26-29 ?
+ IORAM_WRITE(6, ~READ_PORT(1)); // pins 22-25 ?
+ IORAM_WRITE(7, ~READ_PORT(3)); // pins 30-33
+ break;
+
+ default:
+ logerror("Namco I/O %d: unknown I/O mode %d\n",chip,IORAM_READ(8));
+ }
+}
+
+
+
+static void namco_customio_58XX_run(int chip)
+{
+#if VERBOSE
+ logerror("execute 58XX %d mode %d\n",chip,IORAM_READ(8));
+#endif
+
+ switch (IORAM_READ(8))
+ {
+ case 0: // nop?
+ break;
+
+ case 1: // read switch inputs
+ IORAM_WRITE(4, ~READ_PORT(0)); // pins 38-41
+ IORAM_WRITE(5, ~READ_PORT(1)); // pins 22-25
+ IORAM_WRITE(6, ~READ_PORT(2)); // pins 26-29
+ IORAM_WRITE(7, ~READ_PORT(3)); // pins 30-33
+
+//popmessage("%x %x %x %x %x %x %x %x",IORAM_READ(8),IORAM_READ(9),IORAM_READ(10),IORAM_READ(11),IORAM_READ(12),IORAM_READ(13),IORAM_READ(14),IORAM_READ(15));
+
+ WRITE_PORT(0,IORAM_READ(9)); // output to pins 13-16 (toypop)
+ WRITE_PORT(1,IORAM_READ(10)); // output to pins 17-20 (toypop)
+ break;
+
+ case 2: // initialize coinage settings
+ io[chip].coins_per_cred[0] = IORAM_READ(9);
+ io[chip].creds_per_coin[0] = IORAM_READ(10);
+ io[chip].coins_per_cred[1] = IORAM_READ(11);
+ io[chip].creds_per_coin[1] = IORAM_READ(12);
+ // IORAM_READ(13) = 1; meaning unknown - possibly a 3rd coin input? (there's a IPT_UNUSED bit in port A)
+ // IORAM_READ(14) = 0; meaning unknown - possibly a 3rd coin input? (there's a IPT_UNUSED bit in port A)
+ // IORAM_READ(15) = 0; meaning unknown
+ break;
+
+ case 3: // process coin and start inputs, read switch inputs
+ handle_coins(chip,2);
+ break;
+
+ case 4: // read dip switches and inputs
+ WRITE_PORT(0,0); // set pin 13 = 0
+ IORAM_WRITE(0, ~READ_PORT(0)); // pins 38-41, pin 13 = 0
+ IORAM_WRITE(2, ~READ_PORT(1)); // pins 22-25, pin 13 = 0
+ IORAM_WRITE(4, ~READ_PORT(2)); // pins 26-29, pin 13 = 0
+ IORAM_WRITE(6, ~READ_PORT(3)); // pins 30-33, pin 13 = 0
+ WRITE_PORT(0,1); // set pin 13 = 1
+ IORAM_WRITE(1, ~READ_PORT(0)); // pins 38-41, pin 13 = 1
+ IORAM_WRITE(3, ~READ_PORT(1)); // pins 22-25, pin 13 = 1
+ IORAM_WRITE(5, ~READ_PORT(2)); // pins 26-29, pin 13 = 1
+ IORAM_WRITE(7, ~READ_PORT(3)); // pins 30-33, pin 13 = 1
+ break;
+
+ case 5: // bootup check
+ /* mode 5 values are checked against these numbers during power up
+ mappy: 9-15 = 3 6 5 f a c e, expects 1-7 = 8 4 6 e d 9 d
+ grobda: 9-15 = 2 3 4 5 6 7 8, expects 2 = f and 6 = c
+ phozon: 9-15 = 0 1 2 3 4 5 6, expects 0-7 = 0 2 3 4 5 6 c a
+ gaplus: 9-15 = f f f f f f f, expects 0-1 = f f
+
+ This has been determined to be the result of repeated XORs,
+ controlled by a 7-bit LFSR. The following algorithm should be
+ equivalent to the original one (though probably less efficient).
+ The first nibble of the result however is uncertain. It is usually
+ 0, but in some cases it toggles between 0 and F. We use a kludge
+ to give Gaplus the F it expects.
+ */
+ {
+ int i,n,rng,seed;
+ #define NEXT(n) ((((n) & 1) ? (n) ^ 0x90 : (n)) >> 1)
+
+ /* initialize the LFSR depending on the first two arguments */
+ n = (IORAM_READ(9) * 16 + IORAM_READ(10)) & 0x7f;
+ seed = 0x22;
+ for (i = 0;i < n;i++)
+ seed = NEXT(seed);
+
+ /* calculate the answer */
+ for (i = 1;i < 8;i++)
+ {
+ n = 0;
+ rng = seed;
+ if (rng & 1) { n ^= ~IORAM_READ(11); }
+ rng = NEXT(rng);
+ seed = rng; // save state for next loop
+ if (rng & 1) { n ^= ~IORAM_READ(10); }
+ rng = NEXT(rng);
+ if (rng & 1) { n ^= ~IORAM_READ(9); }
+ rng = NEXT(rng);
+ if (rng & 1) { n ^= ~IORAM_READ(15); }
+ rng = NEXT(rng);
+ if (rng & 1) { n ^= ~IORAM_READ(14); }
+ rng = NEXT(rng);
+ if (rng & 1) { n ^= ~IORAM_READ(13); }
+ rng = NEXT(rng);
+ if (rng & 1) { n ^= ~IORAM_READ(12); }
+
+ IORAM_WRITE(i,~n);
+ }
+ IORAM_WRITE(0,0x0);
+ /* kludge for gaplus */
+ if (IORAM_READ(9) == 0xf) IORAM_WRITE(0,0xf);
+ }
+ break;
+
+ default:
+ logerror("Namco I/O %d: unknown I/O mode %d\n",chip,IORAM_READ(8));
+ }
+}
+
+
+
+READ8_HANDLER( namcoio_r )
+{
+ // RAM is 4-bit wide; Pac & Pal requires the | 0xf0 otherwise Easter egg doesn't work
+ offset &= 0x3f;
+
+#if VERBOSE
+ logerror("%04x: I/O read %d: mode %d, offset %d = %02x\n", activecpu_get_pc(), offset / 16, namcoio_ram[(offset & 0x30) + 8], offset & 0x0f, namcoio_ram[offset]&0x0f);
+#endif
+
+ return 0xf0 | namcoio_ram[offset];
+}
+
+WRITE8_HANDLER( namcoio_w )
+{
+ offset &= 0x3f;
+ data &= 0x0f; // RAM is 4-bit wide
+
+#if VERBOSE
+ logerror("%04x: I/O write %d: offset %d = %02x\n", activecpu_get_pc(), offset / 16, offset & 0x0f, data);
+#endif
+
+ namcoio_ram[offset] = data;
+}
+
+void namcoio_set_reset_line(int chipnum, int state)
+{
+ io[chipnum].reset = (state == ASSERT_LINE) ? 1 : 0;
+ if (state != CLEAR_LINE)
+ {
+ /* reset internal registers */
+ io[chipnum].credits = 0;
+ io[chipnum].coins[0] = 0;
+ io[chipnum].coins_per_cred[0] = 1;
+ io[chipnum].creds_per_coin[0] = 1;
+ io[chipnum].coins[1] = 0;
+ io[chipnum].coins_per_cred[1] = 1;
+ io[chipnum].creds_per_coin[1] = 1;
+ io[chipnum].in_count = 0;
+ }
+}
+
+static TIMER_CALLBACK( namcoio_run )
+{
+ switch (io[param].type)
+ {
+ case NAMCOIO_56XX:
+ namco_customio_56XX_run(param);
+ break;
+ case NAMCOIO_58XX:
+ namco_customio_58XX_run(param);
+ break;
+ case NAMCOIO_59XX:
+ namco_customio_59XX_run(param);
+ break;
+ }
+}
+
+void namcoio_set_irq_line(int chipnum, int state)
+{
+ if (chipnum < MAX_NAMCOIO && state != CLEAR_LINE && !io[chipnum].reset)
+ {
+ /* give the cpu a tiny bit of time to write the command before processing it */
+ timer_set(ATTOTIME_IN_USEC(50), chipnum, namcoio_run);
+ }
+}
+
+static void namcoio_state_save(int chipnum)
+{
+
+ state_save_register_item_pointer("namcoio", chipnum, ((UINT8 *) (&namcoio_ram[chipnum * 16])), 16);
+ state_save_register_item("namcoio", chipnum, io[chipnum].reset);
+ state_save_register_item("namcoio", chipnum, io[chipnum].lastcoins);
+ state_save_register_item("namcoio", chipnum, io[chipnum].lastbuttons);
+ state_save_register_item("namcoio", chipnum, io[chipnum].credits);
+ state_save_register_item_array("namcoio", chipnum, io[chipnum].coins);
+ state_save_register_item_array("namcoio", chipnum, io[chipnum].coins_per_cred);
+ state_save_register_item_array("namcoio", chipnum, io[chipnum].creds_per_coin);
+ state_save_register_item("namcoio", chipnum, io[chipnum].in_count);
+ state_save_register_item("namcoio", chipnum, io[chipnum].mode);
+ state_save_register_item("namcoio", chipnum, io[chipnum].coincred_mode);
+ state_save_register_item("namcoio", chipnum, io[chipnum].remap_joy);
+}
+
+void namcoio_init(int chipnum, int type, const struct namcoio_interface *intf)
+{
+ if (chipnum < MAX_NAMCOIO)
+ {
+ io[chipnum].type = type;
+ io[chipnum].in[0] = (intf && intf->in[0]) ? intf->in[0] : nop_r;
+ io[chipnum].in[1] = (intf && intf->in[1]) ? intf->in[1] : nop_r;
+ io[chipnum].in[2] = (intf && intf->in[2]) ? intf->in[2] : nop_r;
+ io[chipnum].in[3] = (intf && intf->in[3]) ? intf->in[3] : nop_r;
+ io[chipnum].out[0] = (intf && intf->out[0]) ? intf->out[0] : nop_w;
+ io[chipnum].out[1] = (intf && intf->out[1]) ? intf->out[1] : nop_w;
+ namcoio_state_save(chipnum);
+ namcoio_set_reset_line(chipnum,PULSE_LINE);
+ }
+}
+
+
+
+
+
+
+
+static TIMER_CALLBACK( nmi_generate )
+{
+ if (!cpunum_is_suspended(param, SUSPEND_REASON_HALT | SUSPEND_REASON_RESET | SUSPEND_REASON_DISABLE))
+ {
+#if VERBOSE
+ logerror("NMI cpu %d\n",nmi_cpu[param]);
+#endif
+
+ cpunum_set_input_line(nmi_cpu[param], INPUT_LINE_NMI, PULSE_LINE);
+ }
+#if VERBOSE
+ else
+ logerror("NMI not generated because cpu %d is suspended\n",nmi_cpu[param]);
+#endif
+}
+
+static UINT8 customio_command[MAX_06XX];
+
+static void namco_06xx_state_save(int chipnum)
+{
+
+ //state_save_register_item("namcoio06xx", chipnum, nmi_cpu[chipnum]);
+ state_save_register_item("namcoio06xx", chipnum, customio_command[chipnum]);
+}
+
+
+void namco_06xx_init(int chipnum, int cpu,
+ int type0, const struct namcoio_interface *intf0,
+ int type1, const struct namcoio_interface *intf1,
+ int type2, const struct namcoio_interface *intf2,
+ int type3, const struct namcoio_interface *intf3)
+{
+ if (chipnum < MAX_06XX)
+ {
+ namcoio_init(4*chipnum + 0, type0, intf0);
+ namcoio_init(4*chipnum + 1, type1, intf1);
+ namcoio_init(4*chipnum + 2, type2, intf2);
+ namcoio_init(4*chipnum + 3, type3, intf3);
+ nmi_cpu[chipnum] = cpu;
+ nmi_timer[chipnum] = timer_alloc(nmi_generate);
+ namco_06xx_state_save(chipnum);
+ }
+}
+
+
+
+static UINT8 namcoio_53XX_digdug_read(int chip)
+{
+#if VERBOSE
+ logerror("%04x: custom 53XX read\n",activecpu_get_pc());
+#endif
+
+ switch ((io[chip].in_count++) % 2)
+ {
+ default:
+ case 0: return READ_PORT(0) | (READ_PORT(1) << 4);
+ case 1: return READ_PORT(2) | (READ_PORT(3) << 4);
+ }
+}
+
+
+static UINT8 namcoio_53XX_polepos_read(int chip)
+{
+#if VERBOSE
+ logerror("%04x: custom 53XX read\n",activecpu_get_pc());
+#endif
+
+ switch ((io[chip].in_count++) % 8)
+ {
+ case 0: return READ_PORT(0) | (READ_PORT(1) << 4); // steering
+ case 4: return READ_PORT(2) | (READ_PORT(3) << 4); // dip switches
+ default: return 0xff; // polepos2 hangs if 0 is returned
+ }
+}
+
+
+static UINT8 namco_06xx_data_read(int chipnum)
+{
+#if VERBOSE
+ logerror("forwarding read to chip %d\n",chipnum%3);
+#endif
+
+ switch (io[chipnum].type)
+ {
+ case NAMCOIO_50XX: return namco_50xx_read();
+ case NAMCOIO_50XX_2: return namco_50xx_2_read();
+ case NAMCOIO_51XX: return namcoio_51XX_read(chipnum);
+ case NAMCOIO_53XX_DIGDUG: return namcoio_53XX_digdug_read(chipnum);
+ case NAMCOIO_53XX_POLEPOS: return namcoio_53XX_polepos_read(chipnum);
+ default:
+ logerror("%04x: custom IO type %d unsupported read\n",activecpu_get_pc(),io[chipnum].type);
+ return 0xff;
+ }
+}
+
+
+static void namco_06xx_data_write(int chipnum,UINT8 data)
+{
+#if VERBOSE
+ logerror("forwarding write to chip %d\n",chipnum%3);
+#endif
+
+ switch (io[chipnum].type)
+ {
+ case NAMCOIO_50XX: namco_50xx_write(data); break;
+ case NAMCOIO_50XX_2: namco_50xx_2_write(data); break;
+ case NAMCOIO_51XX: namcoio_51XX_write(chipnum,data); break;
+ case NAMCOIO_52XX: namcoio_52XX_write(data); break;
+ case NAMCOIO_54XX: namco_54xx_write(data); break;
+ default:
+ logerror("%04x: custom IO type %d unsupported write\n",activecpu_get_pc(),io[chipnum].type);
+ break;
+ }
+}
+
+
+static void namco_06xx_read_request(int chipnum)
+{
+#if VERBOSE
+ logerror("requesting read to chip %d\n",chipnum%3);
+#endif
+
+ switch (io[chipnum].type)
+ {
+ case NAMCOIO_50XX: namco_50xx_read_request(); break;
+ case NAMCOIO_50XX_2: namco_50xx_2_read_request(); break;
+ default:
+ logerror("%04x: custom IO type %d read_request unsupported\n",activecpu_get_pc(),io[chipnum].type);
+ break;
+ }
+}
+
+
+static UINT8 namco_06xx_data_r(int chip,int offset)
+{
+#if VERBOSE
+ logerror("%04x: 06XX #%d read offset %d\n",activecpu_get_pc(),chip,offset);
+#endif
+
+ if (!(customio_command[chip] & 0x10))
+ {
+ logerror("%04x: 06XX #%d read in write mode %02x\n",activecpu_get_pc(),chip,customio_command[chip]);
+ return 0;
+ }
+
+ switch (customio_command[chip] & 0xf)
+ {
+ case 0x1: return namco_06xx_data_read(4*chip + 0); break;
+ case 0x2: return namco_06xx_data_read(4*chip + 1); break;
+ case 0x4: return namco_06xx_data_read(4*chip + 2); break;
+ case 0x8: return namco_06xx_data_read(4*chip + 3); break;
+ default:
+ logerror("%04x: 06XX #%d read in unsupported mode %02x\n",activecpu_get_pc(),chip,customio_command[chip]);
+ return 0xff;
+ }
+}
+
+
+static void namco_06xx_data_w(int chip,int offset,int data)
+{
+#if VERBOSE
+ logerror("%04x: 06XX #%d write offset %d = %02x\n",activecpu_get_pc(),chip,offset,data);
+#endif
+
+ if (customio_command[chip] & 0x10)
+ {
+ logerror("%04x: 06XX #%d write in read mode %02x\n",activecpu_get_pc(),chip,customio_command[chip]);
+ return;
+ }
+
+ switch (customio_command[chip] & 0xf)
+ {
+ case 0x1: namco_06xx_data_write(4*chip + 0,data); break;
+ case 0x2: namco_06xx_data_write(4*chip + 1,data); break;
+ case 0x4: namco_06xx_data_write(4*chip + 2,data); break;
+ case 0x8: namco_06xx_data_write(4*chip + 3,data); break;
+ default:
+ logerror("%04x: 06XX #%d write in unsupported mode %02x\n",activecpu_get_pc(),chip,customio_command[chip]);
+ break;
+ }
+}
+
+
+static UINT8 namco_06xx_ctrl_r(int chip)
+{
+#if VERBOSE
+ logerror("%04x: 06XX #%d ctrl_r\n",activecpu_get_pc(),chip);
+#endif
+ return customio_command[chip];
+}
+
+static void namco_06xx_ctrl_w(int chip,int data)
+{
+#if VERBOSE
+ logerror("%04x: 06XX #%d command %02x\n",activecpu_get_pc(),chip,data);
+#endif
+
+ customio_command[chip] = data;
+
+ if ((customio_command[chip] & 0x0f) == 0)
+ {
+#if VERBOSE
+ logerror("disabling nmi generate timer\n");
+#endif
+ timer_adjust(nmi_timer[chip], attotime_never, chip, attotime_never);
+ }
+ else
+ {
+#if VERBOSE
+ logerror("setting nmi generate timer to 200us\n");
+#endif
+ // this timing is critical. Due to a bug, Bosconian will stop responding to
+ // inputs if a transfer terminates at the wrong time.
+ // On the other hand, the time cannot be too short otherwise the 54XX will
+ // not have enough time to process the incoming commands.
+ timer_adjust(nmi_timer[chip], ATTOTIME_IN_USEC(200), chip, ATTOTIME_IN_USEC(200));
+
+ if (customio_command[chip] & 0x10)
+ {
+ switch (customio_command[chip] & 0xf)
+ {
+ case 0x1: namco_06xx_read_request(4*chip + 0); break;
+ case 0x2: namco_06xx_read_request(4*chip + 1); break;
+ case 0x4: namco_06xx_read_request(4*chip + 2); break;
+ case 0x8: namco_06xx_read_request(4*chip + 3); break;
+ default:
+ logerror("%04x: 06XX #%d read in unsupported mode %02x\n",activecpu_get_pc(),chip,customio_command[chip]);
+ }
+ }
+ }
+}
+
+
+
+READ8_HANDLER( namco_06xx_0_data_r ) { return namco_06xx_data_r(0,offset); }
+READ8_HANDLER( namco_06xx_1_data_r ) { return namco_06xx_data_r(1,offset); }
+WRITE8_HANDLER( namco_06xx_0_data_w ) { namco_06xx_data_w(0,offset,data); }
+WRITE8_HANDLER( namco_06xx_1_data_w ) { namco_06xx_data_w(1,offset,data); }
+READ8_HANDLER( namco_06xx_0_ctrl_r ) { return namco_06xx_ctrl_r(0); }
+READ8_HANDLER( namco_06xx_1_ctrl_r ) { return namco_06xx_ctrl_r(1); }
+WRITE8_HANDLER( namco_06xx_0_ctrl_w ) { namco_06xx_ctrl_w(0,data); }
+WRITE8_HANDLER( namco_06xx_1_ctrl_w ) { namco_06xx_ctrl_w(1,data); }