1 /***************************************************************************
2 
3    cchip.c
4 
5 This file contains routines to interface with the Taito Controller Chip
6 (or "Command Chip") version 1. It's currently used by Superman and Mega
7 Blast. [Further cchip emulation is in machine/rainbow.c, machine/volfied.c,
8 drivers/opwolf.c]
9 
10 According to Richard Bush, the C-Chip is an encrypted Z80 which communicates
11 with the main board as a protection feature.
12 
13 
14 Superman (revised SJ 060601)
15 --------
16 
17 In Superman, the C-chip's main purpose is to handle player inputs and
18 coins and pass commands along to the sound chip.
19 
20 The 68k queries the c-chip, which passes back $100 bytes of 68k code which
21 are then executed in RAM. To get around this, we hack in our own code to
22 communicate with the sound board, since we are familiar with the interface
23 as it's used in Rastan and Super Space Invaders '91.
24 
25 It is believed that the NOPs in the 68k code are there to supply the
26 necessary cycles to the cchip to switch banks.
27 
28 This code requires that the player & coin inputs be in input ports 4-6.
29 
30 
31 Mega Blast
32 ----------
33 
34 C-Chip simply used as RAM, the game doesn't even bother to change banks.
35 It does read the chip id though. The dump is confirmed to be from an
36 original board.
37 
38 ***************************************************************************/
39 
40 #include "driver.h"
41 #include "state.h"
42 
43 static int current_bank = 0;
44 
45 static UINT8 cc_port = 0;
46 
47 /* This code for sound communication is a hack, it will not be
48    identical to the code derived from the real c-chip */
49 
50 static UINT8 superman_code[40] =
51 {
52 	0x48, 0xe7, 0x80, 0x80,	            /* MOVEM.L  D0/A0,-(A7)   ( Preserve Regs ) */
53 	0x20, 0x6d, 0x1c, 0x40,             /* MOVEA.L  ($1C40,A5),A0 ( Load sound pointer in A0 ) */
54 	0x30, 0x2f, 0x00, 0x0c,             /* MOVE.W   ($0C,A7),D0   ( Fetch sound number ) */
55 	0x10, 0x80,                         /* MOVE.B   D0,(A0)       ( Store it on sound pointer ) */
56 	0x52, 0x88,                         /* ADDQ.W   #1,A0         ( Increment sound pointer ) */
57 	0x20, 0x3c, 0x00, 0xf0, 0x1c, 0x40, /* MOVE.L   #$F01C40,D0   ( Load top of buffer in D0 ) */
58 	0xb1, 0xc0,                         /* CMPA.L   D0,A0         ( Are we there yet? ) */
59 	0x66, 0x04,                         /* BNE.S    *+$6          ( No, we arent, skip next line ) */
60 	0x41, 0xed, 0x1c, 0x20,             /* LEA      ($1C20,A5),A0 ( Point to the start of the buffer ) */
61 	0x2b, 0x48, 0x1c, 0x40,	            /* MOVE.L   A0,($1C40,A5) ( Store new sound pointer ) */
62 	0x4c, 0xdf, 0x01, 0x01,	            /* MOVEM.L  (A7)+, D0/A0  ( Restore Regs ) */
63 	0x4e, 0x75                          /* RTS                    ( Return ) */
64 };
65 
MACHINE_INIT(cchip1)66 MACHINE_INIT( cchip1 )
67 {
68 	state_save_register_int  ("cchip1", 0, "current_bank", &current_bank);
69 	state_save_register_UINT8("cchip1", 0, "cc_port",      &cc_port, 1);
70 }
71 
WRITE16_HANDLER(cchip1_word_w)72 WRITE16_HANDLER( cchip1_word_w )
73 {
74 	if (offset == 0x600)
75 	{
76 		current_bank = data;
77 	}
78 	else if (current_bank == 0 && offset == 0x003)
79 	{
80 		cc_port = data;
81 
82 		coin_lockout_w(1, data & 0x08);
83 		coin_lockout_w(0, data & 0x04);
84 		coin_counter_w(1, data & 0x02);
85 		coin_counter_w(0, data & 0x01);
86 	}
87 	else
88 	{
89 log_cb(RETRO_LOG_DEBUG, LOGPRE "cchip1_w pc: %06x bank %02x offset %04x: %02x\n",activecpu_get_pc(),current_bank,offset,data);
90 	}
91 }
92 
READ16_HANDLER(cchip1_word_r)93 READ16_HANDLER( cchip1_word_r )
94 {
95 	/* C-Chip ID */
96 
97 	if (offset == 0x401)
98 	{
99 		return 0x01;
100 	}
101 
102 	/* Check for input ports */
103 
104 	if (current_bank == 0)
105 	{
106 		switch (offset)
107 		{
108 			case 0x000: return readinputport(4);
109 			case 0x001: return readinputport(5);
110 			case 0x002: return readinputport(6);
111 			case 0x003: return cc_port;
112 		}
113 	}
114 
115 	/* Other non-standard offsets */
116 
117 	if (current_bank == 1 && offset <= 0xff)
118 	{
119 		if (offset < 40)	/* our hack code is only 40 bytes long */
120 			return superman_code[offset];
121 		else	/* so pad with zeros */
122 			return 0;
123 	}
124 
125 	if (current_bank == 2)
126 	{
127 		switch (offset)
128 		{
129 			case 0x000: return 0x47;
130 			case 0x001: return 0x57;
131 			case 0x002: return 0x4b;
132 		}
133 	}
134 
135 log_cb(RETRO_LOG_DEBUG, LOGPRE "cchip1_r bank: %02x offset: %04x\n",current_bank,offset);
136 	return 0;
137 }
138 
139 
140 /* Mega Blast */
141 
142 data16_t *cchip_ram;
143 
WRITE16_HANDLER(cchip2_word_w)144 WRITE16_HANDLER( cchip2_word_w )
145 {
146     log_cb(RETRO_LOG_DEBUG, LOGPRE "cchip2_w pc: %06x offset %04x: %02x\n", activecpu_get_pc(), offset, data);
147 
148     COMBINE_DATA(&cchip_ram[offset]);
149 }
150 
READ16_HANDLER(cchip2_word_r)151 READ16_HANDLER( cchip2_word_r )
152 {
153 	/* C-Chip ID */
154 
155 	if (offset == 0x401)
156 	{
157 		return 0x01;
158 	}
159 
160 	log_cb(RETRO_LOG_DEBUG, LOGPRE "cchip2_r offset: %04x\n", offset);
161 
162 	return cchip_ram[offset];
163 }
164