1 // license:BSD-3-Clause
2 // copyright-holders:Jonathan Gevaryahu, David Haywood
3 
4 /*
5 
6 TC0030CMD "C-chip" pinout: (from operation wolf schematics)
7 http://www.arcade-museum.com/manuals-videogames/O/Operation%20Wolf%20Schematics.pdf
8 http://www.jammarcade.net/partial-rainbow-islands-schematic/
9 
10 Chip contains 4 dies:
11 (starting from pin 1 edge going toward pin 32 edge)
12 1 - uPD78C11 MCU w/ 4kx8 mask rom (assumed to be the same between games)
13 2 - uPD27C64 8kx8 EPROM (assumed to be different between games)
14 3 - uPD4464 8kx8 SRAM
15 4 - ASIC of some sort
16 
17 
18                          +---------\_/---------+
19                 VCC -- - |  1               64 | - -- VCC
20                 PA0 <> m |  2               63 | m <- AN7 (tied to GND externally)
21                 PA1 <> m |  3               62 | m <- AN6
22                 PA2 <> m |  4               61 | m <- AN5
23                 PA3 <> m |  5               60 | m <- AN4
24                 PA4 <> m |  6               59 | m <- AN3
25                 PA5 <> m |  7               58 | m <- AN2 (tied to VCC externally)
26                 PA6 <> m |  8     T         57 | m <- AN1
27                 PA7 <> m |  9             | 56 | m <- AN0
28                 PB0 <> m | 10     C    ---| 55 | m <- MODE1 (MODE0 and AVSS are internally tied to GND) **
29                 PB1 <> m | 11             | 54 | m <- /INT1
30                 PB2 <> m | 12     0    --\  53 | m <- /NMI, used on rainbow islands
31                 PB3 <> m | 13           | > 52 | m <> PC7
32                 PB4 <> m | 14     0    --/  51 | m <> PC6
33                 PB5 <> m | 15               50 | m <> PC5
34                 PB6 <> m | 16     3    ---- 49 | m <> PC4
35                 PB7 <> m | 17               48 | m <> PC3
36                 PC0 <> m | 18     0       | 47 | m <> PC2
37   (tied to VCC) VPP -> e | 19          ---| 46 | m <> PC1
38                 CLK -> a | 20     C       | 45 | a <- A10
39       *ASIC_MODESEL ?> a | 21          /--\ 44 | a <- A9
40              /RESET -> a | 22     M    |  | 43 | a <- A8
41                  D0 <> a | 23          \--/ 42 | a <- A7
42                  D1 <> a | 24     D         41 | a <- A6
43                  D2 <> a | 25               40 | a <- A5
44                  D3 <> a | 26               39 | a <- A4
45                  D4 <> a | 27               38 | a <- A3
46                  D5 <> a | 28               37 | a <- A2
47                  D6 <> a | 29               36 | a <- A1
48                  D7 <> a | 30               35 | a <- A0
49                 /CS -> a | 31               34 | a -> DTACK out to 68k (/CDTA)
50                 GND -- - | 32               33 | a <- R/W
51                          +---------------------+
52 a = to asic
53 e = to eprom
54 m = to mcu
55 - = power pins, common
56 
57 CLK is supplied with a 12MHZ oscillator on operation wolf
58 
59 *Pin 21 goes to the ASIC and may be a mode pin. (try holding it to gnd?) Normally tied to 5v thru a 1k resistor.
60 
61 ** MODE1 is normally tied high externally via a 330ohm resistor, but can be in either state.
62    MODE0 on the c-chip is internally tied low.
63 
64 (move below MODE notes to upd7811.cpp?)
65 
66 The four Mode0/Mode1 combinations are:
67     LOW/LOW     78c11 mem map is 4k external rom (i.e. the eprom inside the c-chip) from 0x0000-0x0FFF;
68                 the low 4 bits of port F are used, to provide the high 4 address bits.
69                 speculation: likely the eprom can be banked so the low or high half is visible here,
70                 or possibly one fixed window and 3 variable windows, managed by the asic?
71     LOW/HIGH    78c11 mem map boots to internal rom (mask rom inside the 78c11 inside the c-chip) from
72                 0x0000-0x0fff but the memory map is under full mcu control and can select any of the
73                 four modes (internal only, 4k external, 16k external, 64k external)
74 The following two modes are unusable on the c-chip:
75     HIGH/LOW    78c11 mem map is 16k external rom from 0x0000-0x3FFF;
76                 the low 6 bits of port F are used, to provide the high 6 address bits.
77     HIGH/HIGH   78c11 mem map is 64k external rom from 0x0000-0xFFFF;
78                 all 8 bits of port F are used to provide the high 8 address bits.
79 VPP is only used for programming the 27c64, do not tie it to 18v or you will probably overwrite the 27c64 with garbage.
80 
81 (see http://www.cpcwiki.eu/index.php/UPD7810/uPD7811 )
82 
83 
84 C-chip EXTERNAL memory map (it acts as a device mapped to ram; dtack is asserted on /cs for a 68k):
85 0x000-0x3FF = RW ram window, a 1k window into the 8k byte sram inside the c-chip; the 'bank' visible is selected by 0x600 below
86 0x400-0x403 = "ASIC RAM", 4 bytes of ram on the asic
87 0x400 = unknown, no idea if /DTACK is asserted for R or W here
88 0x401 = RW 'test command/status register', writing a 0x02 here starts test mode, will return 0x01 set if ok/ready for
89     command and 0x04 set if error; this register is very likely handled by the internal rom in the upd78c11 itself rather
90     than the eprom, and probably tests the sram and the 78c11 internal ram, among other things.
91     * Current guess: 0x401 is actually attached to the high 2 bits of the PF register; bit 0 is pf6 out, bit 1 is pf6 in
92       (attached to pf6 thru a resistor?), bit 2 is pf7 out, bit 3 is pf7 in (attached to pf7 through a resistor).
93       The 78c11 (I'm guessing) reads pf6 and pf7 once per int; if pf6-in is set it reruns the startup selftest,
94       clears pf6-out, then re-sets it. if there is an error, it also sets pf7.
95     * Alternate guess: pf4 selects between rom and ram but pf5,6,7 are all mapped to 0x401. a memory mapped register in
96       upd78c11 space selects low vs high half of rom/ram access
97 0x402-0x5ff = unknown (may be mirror of 0x400 and 0x401?) no idea if /DTACK is asserted for R or W here
98 0x600 = ?W ram window bank select, selects one of 8 1k banks to be accessible at 0x000-0x3ff , only low 3 bits are valid on this register. not sure if readable.
99 0x601-0x7ff = unknown, no idea if /DTACK is asserted for R or W here
100 
101 This chip *ALWAYS* has a bypass capacitor (ceramic, 104, 0.10 uF) soldered on top of the chip between pins 1 and 32 OR between 64 and 32.
102 
103 */
104 
105 #include "emu.h"
106 #include "machine/taitocchip.h"
107 
108 #include "cpu/upd7810/upd7811.h"
109 
110 
111 DEFINE_DEVICE_TYPE(TAITO_CCHIP, taito_cchip_device, "cchip", "Taito TC0030CMD (C-Chip)")
112 
taito_cchip_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)113 taito_cchip_device::taito_cchip_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
114 	device_t(mconfig, TAITO_CCHIP, tag, owner, clock),
115 	m_upd7811(*this, "upd7811"),
116 	m_upd4464_bank(*this, "upd4464_bank"),
117 	m_upd4464_bank68(*this, "upd4464_bank68"),
118 	m_upd4464(*this, "upd4464"),
119 	m_in_pa_cb(*this),
120 	m_in_pb_cb(*this),
121 	m_in_pc_cb(*this),
122 	m_in_ad_cb(*this),
123 	m_out_pa_cb(*this),
124 	m_out_pb_cb(*this),
125 	m_out_pc_cb(*this)
126 {
127 }
128 
ext_interrupt(int state)129 void taito_cchip_device::ext_interrupt(int state)
130 {
131 	m_upd7811->set_input_line(UPD7810_INTF1, state);
132 }
133 
134 ROM_START( taito_cchip )
135 	ROM_REGION( 0x1000, "upd7811", 0 )
136 	// optically extracted, the internal checksum passes, although that doesn't rule out the possibility of error
137 	ROM_LOAD( "cchip_upd78c11.bin", 0x0000, 0x1000, CRC(43021521) SHA1(73bc4b46cd2d6805ec926f39f22af00e38a3f822) )
138 ROM_END
139 
140 
cchip_ram_bank(address_map & map)141 void taito_cchip_device::cchip_ram_bank(address_map &map)
142 {
143 	map(0x0000, 0x1fff).ram().share("upd4464"); // upd4464
144 }
145 
cchip_ram_bank68(address_map & map)146 void taito_cchip_device::cchip_ram_bank68(address_map &map)
147 {
148 	map(0x0000, 0x1fff).ram().share("upd4464");
149 }
150 
asic_r(offs_t offset)151 u8 taito_cchip_device::asic_r(offs_t offset)
152 {
153 	if ((offset != 0x001) && (!machine().side_effects_disabled())) // prevent logerror spam for now
154 		logerror("%s: asic_r %04x\n", machine().describe_context(), offset);
155 	if (offset<0x200) // 400-5ff is asic 'ram'
156 		return m_asic_ram[offset&3];
157 	return 0x00; // 600-7ff is write-only(?) asic banking reg, may read as open bus or never assert /DTACK on read?
158 }
159 
asic_w(offs_t offset,u8 data)160 void taito_cchip_device::asic_w(offs_t offset, u8 data)
161 {
162 	//logerror("%s: asic_w %04x %02x\n", machine().describe_context(), offset, data);
163 	if (offset == 0x200)
164 	{
165 		//logerror("cchip set bank to %02x\n", data & 0x7);
166 		m_upd4464_bank->set_bank(data & 0x7);
167 	}
168 	else
169 	{
170 		m_asic_ram[offset & 3] = data;
171 	}
172 }
173 
asic68_w(offs_t offset,u8 data)174 void taito_cchip_device::asic68_w(offs_t offset, u8 data)
175 {
176 	//logerror("%s: asic68_w %04x %02x\n", machine().describe_context(), offset, data);
177 	if (offset == 0x200)
178 	{
179 		//logerror("cchip (68k side) set bank to %02x\n", data & 0x7);
180 		m_upd4464_bank68->set_bank(data & 0x7);
181 	}
182 	else
183 	{
184 		m_asic_ram[offset & 3] = data;
185 	}
186 }
187 
mem_r(offs_t offset)188 u8 taito_cchip_device::mem_r(offs_t offset)
189 {
190 	return m_upd4464_bank->read8(offset & 0x03ff);
191 }
192 
mem_w(offs_t offset,u8 data)193 void taito_cchip_device::mem_w(offs_t offset, u8 data)
194 {
195 	return m_upd4464_bank->write8(offset & 0x03ff, data);
196 }
197 
mem68_r(offs_t offset)198 u8 taito_cchip_device::mem68_r(offs_t offset)
199 {
200 	return m_upd4464_bank68->read8(offset & 0x03ff);
201 }
202 
mem68_w(offs_t offset,u8 data)203 void taito_cchip_device::mem68_w(offs_t offset, u8 data)
204 {
205 	return m_upd4464_bank68->write8(offset & 0x03ff, data);
206 }
207 
cchip_map(address_map & map)208 void taito_cchip_device::cchip_map(address_map &map)
209 {
210 	//map(0x0000, 0x0fff).rom(); // internal ROM of uPD7811
211 	map(0x1000, 0x13ff).m(m_upd4464_bank, FUNC(address_map_bank_device::amap8));
212 	map(0x1400, 0x17ff).rw(FUNC(taito_cchip_device::asic_r), FUNC(taito_cchip_device::asic_w));
213 	map(0x2000, 0x3fff).rom().region("cchip_eprom", 0);
214 }
215 
216 
217 
device_add_mconfig(machine_config & config)218 void taito_cchip_device::device_add_mconfig(machine_config &config)
219 {
220 	upd78c11_device &upd(UPD78C11(config, m_upd7811, DERIVED_CLOCK(1, 1)));
221 	upd.set_addrmap(AS_PROGRAM, &taito_cchip_device::cchip_map);
222 	upd.pa_in_cb().set([this] { return m_in_pa_cb(); });
223 	upd.pb_in_cb().set([this] { return m_in_pb_cb(); });
224 	upd.pc_in_cb().set([this] { return m_in_pc_cb(); });
225 	upd.pa_out_cb().set([this] (u8 data) { m_out_pa_cb(data); });
226 	upd.pb_out_cb().set([this] (u8 data) { m_out_pb_cb(data); });
227 	upd.pc_out_cb().set([this] (u8 data) { m_out_pc_cb(data); });
228 	upd.pf_out_cb().set([this] (u8 data) { logerror("%s port F written %.2x\n", machine().describe_context(), data); }); // internal? related to locking out the 68k?
229 	upd.an0_func().set([this] { return BIT(m_in_ad_cb(), 0) ? 0xff : 0; });
230 	upd.an1_func().set([this] { return BIT(m_in_ad_cb(), 1) ? 0xff : 0; });
231 	upd.an2_func().set([this] { return BIT(m_in_ad_cb(), 2) ? 0xff : 0; });
232 	upd.an3_func().set([this] { return BIT(m_in_ad_cb(), 3) ? 0xff : 0; });
233 	upd.an4_func().set([this] { return BIT(m_in_ad_cb(), 4) ? 0xff : 0; });
234 	upd.an5_func().set([this] { return BIT(m_in_ad_cb(), 5) ? 0xff : 0; });
235 	upd.an6_func().set([this] { return BIT(m_in_ad_cb(), 6) ? 0xff : 0; });
236 	upd.an7_func().set([this] { return BIT(m_in_ad_cb(), 7) ? 0xff : 0; });
237 
238 	ADDRESS_MAP_BANK(config, m_upd4464_bank, 0);
239 	m_upd4464_bank->set_map(&taito_cchip_device::cchip_ram_bank);
240 	m_upd4464_bank->set_endianness(ENDIANNESS_LITTLE);
241 	m_upd4464_bank->set_data_width(8);
242 	m_upd4464_bank->set_addr_width(13);
243 	m_upd4464_bank->set_stride(0x400);
244 
245 	// the 68k has a different view into the banked memory?
246 	ADDRESS_MAP_BANK(config, m_upd4464_bank68, 0);
247 	m_upd4464_bank68->set_map(&taito_cchip_device::cchip_ram_bank68);
248 	m_upd4464_bank68->set_endianness(ENDIANNESS_LITTLE);
249 	m_upd4464_bank68->set_data_width(8);
250 	m_upd4464_bank68->set_addr_width(13);
251 	m_upd4464_bank68->set_stride(0x400);
252 }
253 
device_resolve_objects()254 void taito_cchip_device::device_resolve_objects()
255 {
256 	m_in_pa_cb.resolve_safe(0);
257 	m_in_pb_cb.resolve_safe(0);
258 	m_in_pc_cb.resolve_safe(0);
259 	m_in_ad_cb.resolve_safe(0);
260 	m_out_pa_cb.resolve_safe();
261 	m_out_pb_cb.resolve_safe();
262 	m_out_pc_cb.resolve_safe();
263 }
264 
device_start()265 void taito_cchip_device::device_start()
266 {
267 	m_upd4464_bank->set_bank(0);
268 	m_upd4464_bank68->set_bank(0);
269 
270 	save_item(NAME(m_asic_ram));
271 	m_asic_ram[0] = m_asic_ram[1] = m_asic_ram[2] = m_asic_ram[3] = 0;
272 }
273 
device_reset()274 void taito_cchip_device::device_reset()
275 {
276 }
277 
device_rom_region() const278 const tiny_rom_entry *taito_cchip_device::device_rom_region() const
279 {
280 	return ROM_NAME(taito_cchip);
281 }
282