1 // license:BSD-3-Clause
2 // copyright-holders:Nicola Salmoria
3 /***************************************************************************
4 
5 The following Namco custom chips are all instances of the same 4-bit MCU,
6 the Fujitsu MB8843 (42-pin DIP package) and MB8842/MB8844 (28-pin DIP),
7 differently programmed.
8 
9 chip  MCU   pins function
10 ---- ------ ---- --------
11 56XX         42  I/O (coin management built-in)
12 58XX         42  I/O (coin management built-in)
13 62XX         28  I/O and explosion (noise) generator
14 
15 16XX interface:
16 ---------------
17 Super Pac Man           56XX  56XX  ----  ----
18 Pac & Pal               56XX  59XX  ----  ----
19 Mappy                   58XX  58XX  ----  ----
20 Phozon                  58XX  56XX  ----  ----
21 The Tower of Druaga     58XX  56XX  ----  ----
22 Grobda                  58XX  56XX  ----  ----
23 Dig Dug II              58XX  56XX  ----  ----
24 Motos                   56XX  56XX  ----  ----
25 Gaplus                  56XX  58XX  62XX  ----
26 Gaplus (alt.)           58XX  56XX  62XX  ----
27 Libble Rabble           58XX  56XX  56XX  ----
28 Toy Pop                 58XX  56XX  56XX  ----
29 
30 
31 Pinouts:
32 
33         MB8843                   MB8842/MB8844
34        +------+                    +------+
35   EXTAL|1   42|Vcc            EXTAL|1   28|Vcc
36    XTAL|2   41|K3              XTAL|2   27|K3
37  /RESET|3   40|K2            /RESET|3   26|K2
38    /IRQ|4   39|K1                O0|4   25|K1
39      SO|5   38|K0                O1|5   24|K0
40      SI|6   37|R15               O2|6   23|R10 /IRQ
41 /SC /TO|7   36|R14               O3|7   22|R9 /TC
42     /TC|8   35|R13               O4|8   21|R8
43      P0|9   34|R12               O5|9   20|R7
44      P1|10  33|R11               O6|10  19|R6
45      P2|11  32|R10               O7|11  18|R5
46      P3|12  31|R9                R0|12  17|R4
47      O0|13  30|R8                R1|13  16|R3
48      O1|14  29|R7               GND|14  15|R2
49      O2|15  28|R6                  +------+
50      O3|16  27|R5
51      O4|17  26|R4
52      O5|18  25|R3
53      O6|19  24|R2
54      O7|20  23|R1
55     GND|21  22|R0
56        +------+
57 
58 
59       O  O  R  R  R  K
60 62XX  O  O  IO O     I
61 
62       P  O  O  R  R  R  R  K
63 56XX  O  O  O  I  I  I  IO I
64 58XX  O  O  O  I  I  I  IO I
65 59XX  O  O  O  I  I  I  IO I
66 
67 
68 Namco custom I/O chips 56XX, 58XX, 59XX
69 
70 These chips work together with a 16XX, that interfaces them with the buffer
71 RAM. Each chip uses 16 nibbles of memory; the 16XX supports up to 4 chips,
72 but most games use only 2.
73 
74 The 56XX, 58XX and 59XX are pin-to-pin compatible, but not functionally equivalent:
75 they provide the same functions, but the command codes and memory addresses
76 are different, so they cannot be exchanged.
77 
78 The devices have 42 pins. There are 16 input lines and 8 output lines to be
79 used for I/O.
80 
81 
82 pin   description
83 ---   -----------
84 1     clock (Mappy, Super Pac-Man)
85 2     clock (Gaplus; equivalent to the above?)
86 3     reset
87 4     irq
88 5-6   (to/from 16XX) (this is probably a normal I/O port used to synchronize with the 16XX)
89 7-8   ?
90 9-12  address to r/w from RAM; 12 also goes to the 16XX and acts as r/w line, so
91       the chip can only read from addresses 0-7 and only write to addresses 8-F
92       (this is probably a normal I/O port used for that purpose)
93 13-16 out port A
94 17-20 out port B
95 21    GND
96 22-25 in port B
97 26-29 in port C
98 30-33 in port D
99 34-37 (to 16XX) probably data to r/w from RAM
100       (this is probably a normal I/O port used for that purpose)
101 38-41 in port A
102 42    Vcc
103 
104 TODO:
105 - It's likely that the 56XX and 58XX chips, when in "coin mode", also internally
106   handle outputs for start lamps, coin counters and coin lockout, like the 51XX.
107   Such lines are NOT present in the Mappy and Super Pacman schematics, so they
108   were probably not used for those games, but they might have been used in
109   others (most likely Gaplus).
110 
111 ***************************************************************************/
112 
113 #include "burnint.h"
114 #include "namcoio.h"
115 #include "driver.h"
116 
117 struct ChipData
118 {
119 	UINT8 (*in_0_cb)(UINT8);
120 	UINT8 (*in_1_cb)(UINT8);
121 	UINT8 (*in_2_cb)(UINT8);
122 	UINT8 (*in_3_cb)(UINT8);
123 	void (*out_0_cb)(UINT8, UINT8);
124 	void (*out_1_cb)(UINT8, UINT8);
125 	void (*run_func)(INT32);
126 	INT32 type;
127 
128 	UINT8	ram[16];
129 	INT32	reset;
130 	INT32	lastcoins;
131 	INT32	lastbuttons;
132 	INT32	credits;
133 	INT32	coins[2];
134 	INT32	coins_per_cred[2];
135 	INT32	creds_per_coin[2];
136 	INT32	in_count;
137 };
138 
139 static struct ChipData Chips[5];
140 
fakeIn(UINT8)141 static UINT8 fakeIn(UINT8) { return 0; }
fakeOut(UINT8,UINT8)142 static void fakeOut(UINT8,UINT8) { }
143 
namcoio_init(INT32 chip,INT32 type,UINT8 (* in0)(UINT8),UINT8 (* in1)(UINT8),UINT8 (* in2)(UINT8),UINT8 (* in3)(UINT8),void (* out0)(UINT8,UINT8),void (* out1)(UINT8,UINT8))144 void namcoio_init(INT32 chip, INT32 type, UINT8 (*in0)(UINT8), UINT8 (*in1)(UINT8), UINT8 (*in2)(UINT8), UINT8 (*in3)(UINT8), void (*out0)(UINT8, UINT8), void (*out1)(UINT8, UINT8))
145 {
146 	ChipData *ptr = &Chips[chip];
147 
148 	ptr->type = type;
149 
150 	ptr->in_0_cb = (in0 == NULL) ? fakeIn : in0;
151 	ptr->in_1_cb = (in1 == NULL) ? fakeIn : in1;
152 	ptr->in_2_cb = (in2 == NULL) ? fakeIn : in2;
153 	ptr->in_3_cb = (in3 == NULL) ? fakeIn : in3;
154 	ptr->out_0_cb = (out0 == NULL) ? fakeOut : out0;
155 	ptr->out_1_cb = (out1 == NULL) ? fakeOut : out1;
156 
157 	switch (type)
158 	{
159 		case NAMCO56xx: ptr->run_func = namco56xx_customio_run; break;
160 		case NAMCO58xx: ptr->run_func = namco58xx_customio_run; break;
161 		case NAMCO59xx: ptr->run_func = namco59xx_customio_run; break;
162 	}
163 }
164 
165 //-------------------------------------------------
166 //  device_reset - device-specific reset
167 //-------------------------------------------------
168 
namcoio_set_reset_line(INT32 chip,INT32 state)169 void namcoio_set_reset_line(INT32 chip, INT32 state)
170 {
171 	ChipData *ptr = &Chips[chip];
172 
173 	ptr->reset = (state == ASSERT_LINE) ? 1 : 0;
174 	if (state != CLEAR_LINE)
175 	{
176 		/* reset internal registers */
177 		ptr->credits = 0;
178 		ptr->coins[0] = 0;
179 		ptr->coins_per_cred[0] = 1;
180 		ptr->creds_per_coin[0] = 1;
181 		ptr->coins[1] = 0;
182 		ptr->coins_per_cred[1] = 1;
183 		ptr->creds_per_coin[1] = 1;
184 		ptr->in_count = 0;
185 	}
186 }
187 
namcoio_reset(INT32 chip)188 void namcoio_reset(INT32 chip)
189 {
190 	namcoio_set_reset_line(chip, ASSERT_LINE);
191 	namcoio_set_reset_line(chip, CLEAR_LINE);
192 }
193 
194 /*****************************************************************************
195     DEVICE HANDLERS
196 *****************************************************************************/
197 
198 #define IORAM_READ(offset) (ptr->ram[offset] & 0x0f)
199 #define IORAM_WRITE(offset,data) {ptr->ram[offset] = (data) & 0x0f;}
200 
handle_coins(INT32 chip,int swap)201 static void handle_coins( INT32 chip, int swap )
202 {
203 	int val, toggled;
204 	int credit_add = 0;
205 	int credit_sub = 0;
206 	int button;
207 
208 	ChipData *ptr = &Chips[chip];
209 
210 	val = ~ptr->in_0_cb(0 & 0x0f);    // pins 38-41
211 	toggled = val ^ ptr->lastcoins;
212 	ptr->lastcoins = val;
213 
214 	/* check coin insertion */
215 	if (val & toggled & 0x01)
216 	{
217 		ptr->coins[0]++;
218 		if (ptr->coins[0] >= (ptr->coins_per_cred[0] & 7))
219 		{
220 			credit_add = ptr->creds_per_coin[0] - (ptr->coins_per_cred[0] >> 3);
221 			ptr->coins[0] -= ptr->coins_per_cred[0] & 7;
222 		}
223 		else if (ptr->coins_per_cred[0] & 8)
224 			credit_add = 1;
225 	}
226 	if (val & toggled & 0x02)
227 	{
228 		ptr->coins[1]++;
229 		if (ptr->coins[1] >= (ptr->coins_per_cred[1] & 7))
230 		{
231 			credit_add = ptr->creds_per_coin[1] - (ptr->coins_per_cred[1] >> 3);
232 			ptr->coins[1] -= ptr->coins_per_cred[1] & 7;
233 		}
234 		else if (ptr->coins_per_cred[1] & 8)
235 			credit_add = 1;
236 	}
237 	if (val & toggled & 0x08)
238 	{
239 		credit_add = 1;
240 	}
241 
242 	val = ~ptr->in_3_cb(0 & 0x0f);    // pins 30-33
243 	toggled = val ^ ptr->lastbuttons;
244 	ptr->lastbuttons = val;
245 
246 	/* check start buttons, only if the game allows */
247 	if (IORAM_READ(9) == 0)
248 	// the other argument is IORAM_READ(10) = 1, meaning unknown
249 	{
250 		if (val & toggled & 0x04)
251 		{
252 			if (ptr->credits >= 1) credit_sub = 1;
253 		}
254 		else if (val & toggled & 0x08)
255 		{
256 			if (ptr->credits >= 2) credit_sub = 2;
257 		}
258 	}
259 
260 	ptr->credits += credit_add - credit_sub;
261 
262 	IORAM_WRITE(0 ^ swap, ptr->credits / 10);   // BCD credits
263 	IORAM_WRITE(1 ^ swap, ptr->credits % 10);   // BCD credits
264 	IORAM_WRITE(2 ^ swap, credit_add);  // credit increment (coin inputs)
265 	IORAM_WRITE(3 ^ swap, credit_sub);  // credit decrement (start buttons)
266 	IORAM_WRITE(4, ~ptr->in_1_cb(0 & 0x0f));  // pins 22-25
267 	button = ((val & 0x05) << 1) | (val & toggled & 0x05);
268 	IORAM_WRITE(5, button); // pins 30 & 32 normal and impulse
269 	IORAM_WRITE(6, ~ptr->in_2_cb(0 & 0x0f));  // pins 26-29
270 	button = (val & 0x0a) | ((val & toggled & 0x0a) >> 1);
271 	IORAM_WRITE(7, button); // pins 31 & 33 normal and impulse
272 }
273 
274 
namco56xx_customio_run(INT32 chip)275 void namco56xx_customio_run(INT32 chip)
276 {
277 	ChipData *ptr = &Chips[chip];
278 
279 	switch (IORAM_READ(8))
280 	{
281 		case 1: // read switch inputs
282 			IORAM_WRITE(0, ~ptr->in_0_cb(0 & 0x0f));  // pins 38-41
283 			IORAM_WRITE(1, ~ptr->in_1_cb(0 & 0x0f));  // pins 22-25
284 			IORAM_WRITE(2, ~ptr->in_2_cb(0 & 0x0f));  // pins 26-29
285 			IORAM_WRITE(3, ~ptr->in_3_cb(0 & 0x0f));  // pins 30-33
286 			ptr->out_0_cb((UINT8)0, IORAM_READ(9));   // output to pins 13-16 (motos, pacnpal, gaplus)
287 			ptr->out_1_cb((UINT8)0, IORAM_READ(10));  // output to pins 17-20 (gaplus)
288 		break;
289 
290 		case 2: // initialize coinage settings
291 			ptr->coins_per_cred[0] = IORAM_READ(9);
292 			ptr->creds_per_coin[0] = IORAM_READ(10);
293 			ptr->coins_per_cred[1] = IORAM_READ(11);
294 			ptr->creds_per_coin[1] = IORAM_READ(12);
295 		break;
296 
297 		case 4:
298 			handle_coins(chip,0);
299 		break;
300 
301 		case 7: // bootup check (liblrabl only)
302 			{
303 				IORAM_WRITE(2, 0xe);
304 				IORAM_WRITE(7, 0x6);
305 			}
306 		break;
307 
308 		case 8: // bootup check
309 			{
310 				int i, sum;
311 
312 				sum = 0;
313 				for (i = 9; i < 16; i++)
314 					sum += IORAM_READ(i);
315 				IORAM_WRITE(0, sum >> 4);
316 				IORAM_WRITE(1, sum & 0xf);
317 			}
318 		break;
319 
320 		case 9: // read dip switches and inputs
321 			ptr->out_0_cb((UINT8)0, 0 & 0x0f);   // set pin 13 = 0
322 			IORAM_WRITE(0, ~ptr->in_0_cb(0 & 0x0f));  // pins 38-41, pin 13 = 0
323 			IORAM_WRITE(2, ~ptr->in_1_cb(0 & 0x0f));  // pins 22-25, pin 13 = 0
324 			IORAM_WRITE(4, ~ptr->in_2_cb(0 & 0x0f));  // pins 26-29, pin 13 = 0
325 			IORAM_WRITE(6, ~ptr->in_3_cb(0 & 0x0f));  // pins 30-33, pin 13 = 0
326 			ptr->out_0_cb((UINT8)0, 1 & 0x0f);   // set pin 13 = 1
327 			IORAM_WRITE(1, ~ptr->in_0_cb(0 & 0x0f));  // pins 38-41, pin 13 = 1
328 			IORAM_WRITE(3, ~ptr->in_1_cb(0 & 0x0f));  // pins 22-25, pin 13 = 1
329 			IORAM_WRITE(5, ~ptr->in_2_cb(0 & 0x0f));  // pins 26-29, pin 13 = 1
330 			IORAM_WRITE(7, ~ptr->in_3_cb(0 & 0x0f));  // pins 30-33, pin 13 = 1
331 		break;
332 	}
333 }
334 
namco59xx_customio_run(INT32 chip)335 void namco59xx_customio_run(INT32 chip)
336 {
337 	ChipData *ptr = &Chips[chip];
338 
339 	switch (IORAM_READ(8))
340 	{
341 		case 3: // pacnpal chip #1: read dip switches and inputs
342 			IORAM_WRITE(4, ~ptr->in_0_cb(0 & 0x0f));  // pins 38-41, pin 13 = 0 ?
343 			IORAM_WRITE(5, ~ptr->in_2_cb(0 & 0x0f));  // pins 26-29 ?
344 			IORAM_WRITE(6, ~ptr->in_1_cb(0 & 0x0f));  // pins 22-25 ?
345 			IORAM_WRITE(7, ~ptr->in_3_cb(0 & 0x0f));  // pins 30-33
346 		break;
347 	}
348 }
349 
namco58xx_customio_run(INT32 chip)350 void namco58xx_customio_run(INT32 chip)
351 {
352 	ChipData *ptr = &Chips[chip];
353 
354 	switch (IORAM_READ(8))
355 	{
356 		case 1: // read switch inputs
357 			IORAM_WRITE(4, ~ptr->in_0_cb(0 & 0x0f));  // pins 38-41
358 			IORAM_WRITE(5, ~ptr->in_1_cb(0 & 0x0f));  // pins 22-25
359 			IORAM_WRITE(6, ~ptr->in_2_cb(0 & 0x0f));  // pins 26-29
360 			IORAM_WRITE(7, ~ptr->in_3_cb(0 & 0x0f));  // pins 30-33
361 			ptr->out_0_cb((UINT8)0, IORAM_READ(9));   // output to pins 13-16 (toypop)
362 			ptr->out_1_cb((UINT8)0, IORAM_READ(10));  // output to pins 17-20 (toypop)
363 		break;
364 
365 		case 2: // initialize coinage settings
366 			ptr->coins_per_cred[0] = IORAM_READ(9);
367 			ptr->creds_per_coin[0] = IORAM_READ(10);
368 			ptr->coins_per_cred[1] = IORAM_READ(11);
369 			ptr->creds_per_coin[1] = IORAM_READ(12);
370 		break;
371 
372 		case 3: // process coin and start inputs, read switch inputs
373 			handle_coins(chip,2);
374 		break;
375 
376 		case 4: // read dip switches and inputs
377 			ptr->out_0_cb((UINT8)0, 0 & 0x0f);   // set pin 13 = 0
378 			IORAM_WRITE(0, ~ptr->in_0_cb(0 & 0x0f));  // pins 38-41, pin 13 = 0
379 			IORAM_WRITE(2, ~ptr->in_1_cb(0 & 0x0f));  // pins 22-25, pin 13 = 0
380 			IORAM_WRITE(4, ~ptr->in_2_cb(0 & 0x0f));  // pins 26-29, pin 13 = 0
381 			IORAM_WRITE(6, ~ptr->in_3_cb(0 & 0x0f));  // pins 30-33, pin 13 = 0
382 			ptr->out_0_cb((UINT8)0, 1 & 0x0f);   // set pin 13 = 1
383 			IORAM_WRITE(1, ~ptr->in_0_cb(0 & 0x0f));  // pins 38-41, pin 13 = 1
384 			IORAM_WRITE(3, ~ptr->in_1_cb(0 & 0x0f));  // pins 22-25, pin 13 = 1
385 			IORAM_WRITE(5, ~ptr->in_2_cb(0 & 0x0f));  // pins 26-29, pin 13 = 1
386 			IORAM_WRITE(7, ~ptr->in_3_cb(0 & 0x0f));  // pins 30-33, pin 13 = 1
387 		break;
388 
389 		case 5: // bootup check
390 			{
391 				int i, n, rng, seed;
392 				#define NEXT(n) ((((n) & 1) ? (n) ^ 0x90 : (n)) >> 1)
393 
394 				/* initialize the LFSR depending on the first two arguments */
395 				n = (IORAM_READ(9) * 16 + IORAM_READ(10)) & 0x7f;
396 				seed = 0x22;
397 				for (i = 0; i < n; i++)
398 					seed = NEXT(seed);
399 
400 				/* calculate the answer */
401 				for (i = 1; i < 8; i++)
402 				{
403 					n = 0;
404 					rng = seed;
405 					if (rng & 1) { n ^= ~IORAM_READ(11); }
406 					rng = NEXT(rng);
407 					seed = rng; // save state for next loop
408 					if (rng & 1) { n ^= ~IORAM_READ(10); }
409 					rng = NEXT(rng);
410 					if (rng & 1) { n ^= ~IORAM_READ(9); }
411 					rng = NEXT(rng);
412 					if (rng & 1) { n ^= ~IORAM_READ(15); }
413 					rng = NEXT(rng);
414 					if (rng & 1) { n ^= ~IORAM_READ(14); }
415 					rng = NEXT(rng);
416 					if (rng & 1) { n ^= ~IORAM_READ(13); }
417 					rng = NEXT(rng);
418 					if (rng & 1) { n ^= ~IORAM_READ(12); }
419 
420 					IORAM_WRITE(i, ~n);
421 				}
422 				IORAM_WRITE(0, 0x0);
423 				/* kludge for gaplus */
424 				if (IORAM_READ(9) == 0xf) IORAM_WRITE(0, 0xf);
425 			}
426 		break;
427 	}
428 }
429 
namcoio_run(INT32 chip)430 void namcoio_run(INT32 chip)
431 {
432 	ChipData *ptr = &Chips[chip];
433 
434 	ptr->run_func(chip);
435 }
436 
namcoio_read(INT32 chip,UINT8 offset)437 UINT8 namcoio_read(INT32 chip, UINT8 offset)
438 {
439 	ChipData *ptr = &Chips[chip];
440 
441 	// RAM is 4-bit wide; Pac & Pal requires the | 0xf0 otherwise Easter egg doesn't work
442 	offset &= 0x3f;
443 
444 	return 0xf0 | ptr->ram[offset];
445 }
446 
namcoio_write(INT32 chip,UINT8 offset,UINT8 data)447 void namcoio_write(INT32 chip, UINT8 offset, UINT8 data)
448 {
449 	ChipData *ptr = &Chips[chip];
450 
451 	offset &= 0x3f;
452 	data &= 0x0f;   // RAM is 4-bit wide
453 
454 	ptr->ram[offset] = data;
455 }
456 
namcoio_read_reset_line(INT32 chip)457 UINT8 namcoio_read_reset_line(INT32 chip)
458 {
459 	ChipData *ptr = &Chips[chip];
460 
461 	return ptr->reset;
462 }
463 
namcoio_scan(INT32 chip)464 INT32 namcoio_scan(INT32 chip)
465 {
466 	ChipData *ptr = &Chips[chip];
467 
468 	SCAN_VAR(ptr->ram);
469 	SCAN_VAR(ptr->reset);
470 	SCAN_VAR(ptr->lastcoins);
471 	SCAN_VAR(ptr->lastbuttons);
472 	SCAN_VAR(ptr->coins);
473 	SCAN_VAR(ptr->credits);
474 	SCAN_VAR(ptr->coins_per_cred);
475 	SCAN_VAR(ptr->creds_per_coin);
476 	SCAN_VAR(ptr->in_count);
477 
478 	return 0;
479 }
480