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