1 // license:BSD-3-Clause
2 // copyright-holders:Philip Bennett
3 /**********************************************************************************************
4
5 Taito TC0140SYT
6
7 TODO:
8 - Add pinout and description
9 - Create a separate implementation for the PC060HA
10
11 General rule seems to be that TC0140SYT supports a YM2610,
12 whereas PC060HA goes with a YM2203 or YM2151.
13
14 **********************************************************************************************/
15
16 #include "emu.h"
17 #include "taitosnd.h"
18
19 #include "cpu/z80/z80.h"
20
21
22 /**********************************************************************************************
23
24 It seems like 1 nibble commands are only for control purposes.
25 2 nibble commands are the real messages passed from one board to the other.
26
27 **********************************************************************************************/
28
29 static constexpr u8 TC0140SYT_PORT01_FULL = 0x01;
30 static constexpr u8 TC0140SYT_PORT23_FULL = 0x02;
31 static constexpr u8 TC0140SYT_PORT01_FULL_MASTER = 0x04;
32 static constexpr u8 TC0140SYT_PORT23_FULL_MASTER = 0x08;
33
34
35 // device type definition
36 DEFINE_DEVICE_TYPE(TC0140SYT, tc0140syt_device, "tc0140syt", "Taito TC0140SYT")
37 DEFINE_DEVICE_TYPE(PC060HA, pc060ha_device, "pc060ha", "Taito PC060HA CIU")
38
39
40 //**************************************************************************
41 // LIVE DEVICE
42 //**************************************************************************
43
44 //-------------------------------------------------
45 // tc0140syt_device - constructor
46 //-------------------------------------------------
47
tc0140syt_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,u32 clock)48 tc0140syt_device::tc0140syt_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
49 : device_t(mconfig, type, tag, owner, clock)
50 , m_mainmode(0)
51 , m_submode(0)
52 , m_status(0)
53 , m_nmi_enabled(0)
54 , m_mastercpu(*this, finder_base::DUMMY_TAG)
55 , m_slavecpu(*this, finder_base::DUMMY_TAG)
56 {
57 std::fill(std::begin(m_slavedata), std::end(m_slavedata), 0);
58 std::fill(std::begin(m_masterdata), std::end(m_masterdata), 0);
59 }
60
tc0140syt_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)61 tc0140syt_device::tc0140syt_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
62 : tc0140syt_device(mconfig, TC0140SYT, tag, owner, clock)
63 {
64 }
65
66
67 //-------------------------------------------------
68 // device_start - device-specific startup
69 //-------------------------------------------------
70
device_start()71 void tc0140syt_device::device_start()
72 {
73 save_item(NAME(m_mainmode));
74 save_item(NAME(m_submode));
75 save_item(NAME(m_status));
76 save_item(NAME(m_nmi_enabled));
77 save_item(NAME(m_slavedata));
78 save_item(NAME(m_masterdata));
79 }
80
81
82 //-------------------------------------------------
83 // device_reset - device-specific reset
84 //-------------------------------------------------
85
device_reset()86 void tc0140syt_device::device_reset()
87 {
88 m_mainmode = 0;
89 m_submode = 0;
90 m_status = 0;
91 m_nmi_enabled = 0;
92
93 for (u8 i = 0; i < 4; i++)
94 {
95 m_slavedata[i] = 0;
96 m_masterdata[i] = 0;
97 }
98 }
99
100
101 //-------------------------------------------------
102 // DEVICE HANDLERS
103 //-------------------------------------------------
104
update_nmi()105 void tc0140syt_device::update_nmi()
106 {
107 u32 nmi_pending = m_status & (TC0140SYT_PORT23_FULL | TC0140SYT_PORT01_FULL);
108 u32 state = (nmi_pending && m_nmi_enabled) ? ASSERT_LINE : CLEAR_LINE;
109
110 m_slavecpu->set_input_line(INPUT_LINE_NMI, state);
111 }
112
113
114 //-------------------------------------------------
115 // MASTER SIDE
116 //-------------------------------------------------
117
master_port_w(u8 data)118 void tc0140syt_device::master_port_w(u8 data)
119 {
120 data &= 0x0f;
121 m_mainmode = data;
122
123 if (data > 4)
124 {
125 logerror("tc0140syt : error Master entering unknown mode[%02x]\n", data);
126 }
127 }
128
master_comm_w(u8 data)129 void tc0140syt_device::master_comm_w(u8 data)
130 {
131 machine().scheduler().synchronize(); // let slavecpu catch up (after we return and the main cpu finishes what it's doing)
132 data &= 0x0f; /* this is important, otherwise ballbros won't work */
133
134 switch (m_mainmode)
135 {
136 case 0x00: // mode #0
137 m_slavedata[m_mainmode++] = data;
138 break;
139
140 case 0x01: // mode #1
141 m_slavedata[m_mainmode++] = data;
142 m_status |= TC0140SYT_PORT01_FULL;
143 update_nmi();
144 break;
145
146 case 0x02: // mode #2
147 m_slavedata[m_mainmode++] = data;
148 break;
149
150 case 0x03: // mode #3
151 m_slavedata[m_mainmode++] = data;
152 m_status |= TC0140SYT_PORT23_FULL;
153 update_nmi();
154 break;
155
156 case 0x04: // port status
157 /* this does a hi-lo transition to reset the sound cpu */
158 m_slavecpu->set_input_line(INPUT_LINE_RESET, data ? ASSERT_LINE : CLEAR_LINE);
159 break;
160
161 default:
162 break;
163 }
164 }
165
master_comm_r()166 u8 tc0140syt_device::master_comm_r()
167 {
168 machine().scheduler().synchronize(); // let slavecpu catch up (after we return and the main cpu finishes what it's doing)
169 u8 res = 0;
170
171 switch (m_mainmode)
172 {
173 case 0x00: // mode #0
174 res = m_masterdata[m_mainmode++];
175 break;
176
177 case 0x01: // mode #1
178 m_status &= ~TC0140SYT_PORT01_FULL_MASTER;
179 res = m_masterdata[m_mainmode++];
180 break;
181
182 case 0x02: // mode #2
183 res = m_masterdata[m_mainmode++];
184 break;
185
186 case 0x03: // mode #3
187 m_status &= ~TC0140SYT_PORT23_FULL_MASTER;
188 res = m_masterdata[m_mainmode++];
189 break;
190
191 case 0x04: // port status
192 res = m_status;
193 break;
194
195 default:
196 break;
197 }
198
199 return res;
200 }
201
202
203 //-------------------------------------------------
204 // SLAVE SIDE
205 //-------------------------------------------------
206
slave_port_w(u8 data)207 void tc0140syt_device::slave_port_w(u8 data)
208 {
209 data &= 0x0f;
210 m_submode = data;
211
212 if (data > 6)
213 {
214 logerror("tc0140syt error : Slave cpu unknown mode[%02x]\n", data);
215 }
216 }
217
slave_comm_w(u8 data)218 void tc0140syt_device::slave_comm_w(u8 data)
219 {
220 data &= 0x0f;
221
222 switch (m_submode)
223 {
224 case 0x00: // mode #0
225 m_masterdata[m_submode++] = data;
226 break;
227
228 case 0x01: // mode #1
229 m_masterdata[m_submode++] = data;
230 m_status |= TC0140SYT_PORT01_FULL_MASTER;
231 break;
232
233 case 0x02: // mode #2
234 m_masterdata[m_submode++] = data;
235 break;
236
237 case 0x03: // mode #3
238 m_masterdata[m_submode++] = data;
239 m_status |= TC0140SYT_PORT23_FULL_MASTER;
240 break;
241
242 case 0x04: // port status
243 //m_status = TC0140SYT_SET_OK;
244 break;
245
246 case 0x05: // NMI disable
247 m_nmi_enabled = 0;
248 update_nmi();
249 break;
250
251 case 0x06: // NMI enable
252 m_nmi_enabled = 1;
253 update_nmi();
254 break;
255
256 default:
257 break;
258 }
259 }
260
slave_comm_r()261 u8 tc0140syt_device::slave_comm_r()
262 {
263 u8 res = 0;
264
265 switch (m_submode)
266 {
267 case 0x00: // mode #0
268 res = m_slavedata[m_submode++];
269 break;
270
271 case 0x01: // mode #1
272 m_status &= ~TC0140SYT_PORT01_FULL;
273 res = m_slavedata[m_submode++];
274 update_nmi();
275 break;
276
277 case 0x02: // mode #2
278 res = m_slavedata[m_submode++];
279 break;
280
281 case 0x03: // mode #3
282 m_status &= ~TC0140SYT_PORT23_FULL;
283 res = m_slavedata[m_submode++];
284 update_nmi();
285 break;
286
287 case 0x04: // port status
288 res = m_status;
289 break;
290
291 default:
292 break;
293 }
294
295 return res;
296 }
297
298
299 //-------------------------------------------------
300 // pc060ha_device - constructor
301 //-------------------------------------------------
302
pc060ha_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)303 pc060ha_device::pc060ha_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
304 : tc0140syt_device(mconfig, PC060HA, tag, owner, clock)
305 {
306 }
307