1 #include "driver.h"
2 #include "cpu/z80/z80.h"
3 
4 
5 /**********************************************************************************************
6 
7 	It seems like 1 nibble commands are only for control purposes.
8 	2 nibble commands are the real messages passed from one board to the other.
9 
10 **********************************************************************************************/
11 
12 /* Some logging defines */
13 #if 0
14 #define REPORT_SLAVE_MODE_CHANGE
15 #define REPORT_SLAVE_MODE_READ_ITSELF
16 #define REPORT_MAIN_MODE_READ_SLAVE
17 #define REPORT_DATA_FLOW
18 #endif
19 
20 
21 
22 
23 #define TC0140SYT_PORT01_FULL         (0x01)
24 #define TC0140SYT_PORT23_FULL         (0x02)
25 #define TC0140SYT_PORT01_FULL_MASTER  (0x04)
26 #define TC0140SYT_PORT23_FULL_MASTER  (0x08)
27 
28 typedef struct TC0140SYT
29 {
30 	unsigned char slavedata[4];	/* Data on master->slave port (4 nibbles) */
31 	unsigned char masterdata[4];/* Data on slave->master port (4 nibbles) */
32 	unsigned char mainmode;		/* Access mode on master cpu side */
33 	unsigned char submode;		/* Access mode on slave cpu side */
34 	unsigned char status;		/* Status data */
35 	unsigned char nmi_enabled;	/* 1 if slave cpu has nmi's enabled */
36 	unsigned char nmi_req;		/* 1 if slave cpu has a pending nmi */
37 } TC0140SYT;
38 
39 static struct TC0140SYT tc0140syt;
40 
41 
Interrupt_Controller(void)42 static void Interrupt_Controller(void)
43 {
44 	if ( tc0140syt.nmi_req && tc0140syt.nmi_enabled )
45 	{
46 		cpu_cause_interrupt( 1, Z80_NMI_INT );
47 		tc0140syt.nmi_req = 0;
48 	}
49 }
50 
WRITE_HANDLER(taitosound_port_w)51 WRITE_HANDLER( taitosound_port_w )
52 {
53 	data &= 0x0f;
54 
55 	tc0140syt.mainmode = data;
56 	//logerror("taitosnd: Master cpu mode [%02x]\n", data);
57 	/*if (data > 4)
58 	{
59 		logerror("tc0140syt : error Master entering unknown mode[%02x]\n", data);
60 	}*/
61 }
62 
WRITE_HANDLER(taitosound_comm_w)63 WRITE_HANDLER( taitosound_comm_w )
64 {
65 
66 	data &= 0x0f;	/*this is important, otherwise ballbros won't work*/
67 
68 	switch( tc0140syt.mainmode )
69 	{
70 		case 0x00:		// mode #0
71 			tc0140syt.slavedata[tc0140syt.mainmode ++] = data;
72 			//logerror("taitosnd: Master cpu written port 0, data %01x\n", data);
73 			break;
74 
75 		case 0x01:		// mode #1
76 			tc0140syt.slavedata[tc0140syt.mainmode ++] = data;
77 			tc0140syt.status |= TC0140SYT_PORT01_FULL;
78 			tc0140syt.nmi_req = 1;
79 			//logerror("taitosnd: Master cpu sends 0/1 : %01x%01x\n",tc0140syt.slavedata[1],tc0140syt.slavedata[0]);
80         	break;
81 
82 		case 0x02:		// mode #2
83 			tc0140syt.slavedata[tc0140syt.mainmode ++] = data;
84 			//logerror("taitosnd: Master cpu written port 2, data %01\n", data);
85 			break;
86 
87 		case 0x03:		// mode #3
88 			tc0140syt.slavedata[tc0140syt.mainmode ++] = data;
89 			tc0140syt.status |= TC0140SYT_PORT23_FULL;
90 			tc0140syt.nmi_req = 1;
91 			//logerror("taitosnd: Master cpu sends 2/3 : %01x%01x\n",tc0140syt.slavedata[3],tc0140syt.slavedata[2]);
92 			break;
93 
94 		case 0x04:		// port status
95 //#ifdef REPORT_DATA_FLOW
96 			//logerror("taitosnd: Master issued control value %02x (PC = %08x) \n",data, cpu_get_pc() );
97 //#endif
98 			/* this does a hi-lo transition to reset the sound cpu */
99 			if (data)
100 				cpu_set_reset_line(1,ASSERT_LINE);
101 			else
102 			{
103 				cpu_set_reset_line(1,CLEAR_LINE);
104                 cpu_spin(); /* otherwise no sound in driftout */
105             }
106 			break;
107 
108 		default:
109 			//logerror("taitosnd: Master cpu written in mode [%02x] data[%02x]\n",tc0140syt.mainmode, data);
110 			break;
111 	}
112 
113 }
114 
READ_HANDLER(taitosound_comm_r)115 READ_HANDLER( taitosound_comm_r )
116 {
117 	switch( tc0140syt.mainmode )
118 	{
119 		case 0x00:		// mode #0
120 			//logerror("taitosnd: Master cpu read portdata %01x\n", tc0140syt.masterdata[0]);
121 			return tc0140syt.masterdata[tc0140syt.mainmode ++];
122 			break;
123 
124 		case 0x01:		// mode #1
125 			//logerror("taitosnd: Master cpu receives 0/1 : %01x%01x\n", tc0140syt.masterdata[1],tc0140syt.masterdata[0]);
126 			tc0140syt.status &= ~TC0140SYT_PORT01_FULL_MASTER;
127 			return tc0140syt.masterdata[tc0140syt.mainmode ++];
128 			break;
129 
130 		case 0x02:		// mode #2
131 			//logerror("taitosnd: Master cpu read masterdata %01x\n", tc0140syt.masterdata[2]);
132 			return tc0140syt.masterdata[tc0140syt.mainmode ++];
133 			break;
134 
135 		case 0x03:		// mode #3
136 			//logerror("taitosnd: Master cpu receives 2/3 : %01x%01x\n", tc0140syt.masterdata[3],tc0140syt.masterdata[2]);
137 			tc0140syt.status &= ~TC0140SYT_PORT23_FULL_MASTER;
138 			return tc0140syt.masterdata[tc0140syt.mainmode ++];
139 			break;
140 
141 		case 0x04:		// port status
142 			//logerror("tc0140syt : Master cpu read status : %02x\n", tc0140syt.status);
143 			return tc0140syt.status;
144 			break;
145 
146 		default:
147 			//logerror("tc0140syt : Master cpu read in mode [%02x]\n", tc0140syt.mainmode);
148 			return 0;
149 	}
150 }
151 
152 //SLAVE SIDE
153 
WRITE_HANDLER(taitosound_slave_port_w)154 WRITE_HANDLER( taitosound_slave_port_w )
155 {
156 	data &= 0x0f;
157 	tc0140syt.submode = data;
158 	//logerror("taitosnd: Slave cpu mode [%02x]\n", data);
159 	/*if (data > 6)
160 		logerror("tc0140syt error : Slave cpu unknown mode[%02x]\n", data);*/
161 }
162 
WRITE_HANDLER(taitosound_slave_comm_w)163 WRITE_HANDLER( taitosound_slave_comm_w )
164 {
165 	data &= 0x0f;
166 
167 	switch ( tc0140syt.submode )
168 	{
169 		case 0x00:		// mode #0
170 			tc0140syt.masterdata[tc0140syt.submode ++] = data;
171 			//logerror("taitosnd: Slave cpu written port 0, data %01x\n", data);
172 			break;
173 
174 		case 0x01:		// mode #1
175 			tc0140syt.masterdata[tc0140syt.submode ++] = data;
176 			tc0140syt.status |= TC0140SYT_PORT01_FULL_MASTER;
177 			//logerror("taitosnd: Slave cpu sends 0/1 : %01x%01x\n",tc0140syt.masterdata[1],tc0140syt.masterdata[0]);
178 			cpu_spin(); /* writing should take longer than emulated, so spin */
179 			break;
180 
181 		case 0x02:		// mode #2
182 			//logerror("taitosnd: Slave cpu written port 2, data %01x\n", data);
183 			tc0140syt.masterdata[tc0140syt.submode ++] = data;
184 			break;
185 
186 		case 0x03:		// mode #3
187 			tc0140syt.masterdata[tc0140syt.submode ++] = data;
188 			tc0140syt.status |= TC0140SYT_PORT23_FULL_MASTER;
189 			//logerror("taitosnd: Slave cpu sends 2/3 : %01x%01x\n",tc0140syt.masterdata[3],tc0140syt.masterdata[2]);
190 			cpu_spin(); /* writing should take longer than emulated, so spin */
191 			break;
192 
193 		case 0x04:		// port status
194 			//tc0140syt.status = TC0140SYT_SET_OK;
195 			//logerror("tc0140syt : Slave cpu status ok.\n");
196 			break;
197 
198 		case 0x05:		// nmi disable
199 			tc0140syt.nmi_enabled = 0;
200 			break;
201 
202 		case 0x06:		// nmi enable
203 			tc0140syt.nmi_enabled = 1;
204 			break;
205 
206 		default:
207 			//logerror("tc0140syt: Slave cpu written in mode [%02x] data[%02x]\n",tc0140syt.submode, data & 0xff);
208 			break;
209 	}
210 
211 	Interrupt_Controller();
212 
213 }
214 
READ_HANDLER(taitosound_slave_comm_r)215 READ_HANDLER( taitosound_slave_comm_r )
216 {
217 	unsigned char res = 0;
218 
219 	switch ( tc0140syt.submode )
220 	{
221 		case 0x00:		// mode #0
222 			//logerror("taitosnd: Slave cpu read slavedata %01x\n", tc0140syt.slavedata[0]);
223 			res = tc0140syt.slavedata[tc0140syt.submode ++];
224 			break;
225 
226 		case 0x01:		// mode #1
227 			//logerror("taitosnd: Slave cpu receives 0/1 : %01x%01x PC=%4x\n", tc0140syt.slavedata[1],tc0140syt.slavedata[0],cpu_get_pc());
228 			tc0140syt.status &= ~TC0140SYT_PORT01_FULL;
229 			res = tc0140syt.slavedata[tc0140syt.submode ++];
230 			break;
231 
232 		case 0x02:		// mode #2
233 			//logerror("taitosnd: Slave cpu read slavedata %01x\n", tc0140syt.slavedata[2]);
234 			res = tc0140syt.slavedata[tc0140syt.submode ++];
235 			break;
236 
237 		case 0x03:		// mode #3
238 			//logerror("taitosnd: Slave cpu receives 2/3 : %01x%01x\n", tc0140syt.slavedata[3],tc0140syt.slavedata[2]);
239 			tc0140syt.status &= ~TC0140SYT_PORT23_FULL;
240 			res = tc0140syt.slavedata[tc0140syt.submode ++];
241 			break;
242 
243 		case 0x04:		// port status
244 			//logerror("tc0140syt : Slave cpu read status : %02x\n", tc0140syt.status);
245 			res = tc0140syt.status;
246 			break;
247 
248 		default:
249 			//logerror("tc0140syt : Slave cpu read in mode [%02x]\n", tc0140syt.submode);
250 			res = 0;
251 			break;
252 	}
253 
254 	Interrupt_Controller();
255 
256     return res;
257 }
258 
259 
260 
261 
262 
263 
264 #if 0
265 /* wrapper functions for 16bit handlers */
266 
267 WRITE16_HANDLER( taitosound_port16_lsb_w )
268 {
269 	if (ACCESSING_LSB)
270 		taitosound_port_w(0,data & 0xff);
271 }
272 WRITE16_HANDLER( taitosound_comm16_lsb_w )
273 {
274 	if (ACCESSING_LSB)
275 		taitosound_comm_w(0,data & 0xff);
276 }
277 READ16_HANDLER( taitosound_comm16_lsb_r )
278 {
279 	return taitosound_comm_r(0);
280 }
281 
282 
283 WRITE16_HANDLER( taitosound_port16_msb_w )
284 {
285 	if (ACCESSING_MSB)
286 		taitosound_port_w(0,data >> 8);
287 }
288 WRITE16_HANDLER( taitosound_comm16_msb_w )
289 {
290 	if (ACCESSING_MSB)
291 		taitosound_comm_w(0,data >> 8);
292 }
293 READ16_HANDLER( taitosound_comm16_msb_r )
294 {
295 	return taitosound_comm_r(0) << 8;
296 }
297 #endif
298