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