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_set_irq_line( 1, IRQ_LINE_NMI, PULSE_LINE );
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 		log_cb(RETRO_LOG_DEBUG, LOGPRE "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, activecpu_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 			log_cb(RETRO_LOG_DEBUG, LOGPRE "taitosnd: Master cpu written in mode [%02x] data[%02x]\n",tc0140syt.mainmode, data);
110 	}
111 
112 }
113 
READ_HANDLER(taitosound_comm_r)114 READ_HANDLER( taitosound_comm_r )
115 {
116 	switch( tc0140syt.mainmode )
117 	{
118 		case 0x00:		/* mode #0*/
119 			/*logerror("taitosnd: Master cpu read portdata %01x\n", tc0140syt.masterdata[0]);*/
120 			return tc0140syt.masterdata[tc0140syt.mainmode ++];
121 			break;
122 
123 		case 0x01:		/* mode #1*/
124 			/*logerror("taitosnd: Master cpu receives 0/1 : %01x%01x\n", tc0140syt.masterdata[1],tc0140syt.masterdata[0]);*/
125 			tc0140syt.status &= ~TC0140SYT_PORT01_FULL_MASTER;
126 			return tc0140syt.masterdata[tc0140syt.mainmode ++];
127 			break;
128 
129 		case 0x02:		/* mode #2*/
130 			/*logerror("taitosnd: Master cpu read masterdata %01x\n", tc0140syt.masterdata[2]);*/
131 			return tc0140syt.masterdata[tc0140syt.mainmode ++];
132 			break;
133 
134 		case 0x03:		/* mode #3*/
135 			/*logerror("taitosnd: Master cpu receives 2/3 : %01x%01x\n", tc0140syt.masterdata[3],tc0140syt.masterdata[2]);*/
136 			tc0140syt.status &= ~TC0140SYT_PORT23_FULL_MASTER;
137 			return tc0140syt.masterdata[tc0140syt.mainmode ++];
138 			break;
139 
140 		case 0x04:		/* port status*/
141 			/*logerror("tc0140syt : Master cpu read status : %02x\n", tc0140syt.status);*/
142 			return tc0140syt.status;
143 			break;
144 
145 		default:
146 			log_cb(RETRO_LOG_DEBUG, LOGPRE "tc0140syt : Master cpu read in mode [%02x]\n", tc0140syt.mainmode);
147 			return 0;
148 	}
149 }
150 
151 /*SLAVE SIDE*/
152 
WRITE_HANDLER(taitosound_slave_port_w)153 WRITE_HANDLER( taitosound_slave_port_w )
154 {
155 	data &= 0x0f;
156 	tc0140syt.submode = data;
157 	/*logerror("taitosnd: Slave cpu mode [%02x]\n", data);*/
158 	if (data > 6)
159 		log_cb(RETRO_LOG_DEBUG, LOGPRE "tc0140syt error : Slave cpu unknown mode[%02x]\n", data);
160 }
161 
WRITE_HANDLER(taitosound_slave_comm_w)162 WRITE_HANDLER( taitosound_slave_comm_w )
163 {
164 	data &= 0x0f;
165 
166 	switch ( tc0140syt.submode )
167 	{
168 		case 0x00:		/* mode #0*/
169 			tc0140syt.masterdata[tc0140syt.submode ++] = data;
170 			/*logerror("taitosnd: Slave cpu written port 0, data %01x\n", data);*/
171 			break;
172 
173 		case 0x01:		/* mode #1*/
174 			tc0140syt.masterdata[tc0140syt.submode ++] = data;
175 			tc0140syt.status |= TC0140SYT_PORT01_FULL_MASTER;
176 			/*logerror("taitosnd: Slave cpu sends 0/1 : %01x%01x\n",tc0140syt.masterdata[1],tc0140syt.masterdata[0]);*/
177 			cpu_spin(); /* writing should take longer than emulated, so spin */
178 			break;
179 
180 		case 0x02:		/* mode #2*/
181 			/*logerror("taitosnd: Slave cpu written port 2, data %01x\n", data);*/
182 			tc0140syt.masterdata[tc0140syt.submode ++] = data;
183 			break;
184 
185 		case 0x03:		/* mode #3*/
186 			tc0140syt.masterdata[tc0140syt.submode ++] = data;
187 			tc0140syt.status |= TC0140SYT_PORT23_FULL_MASTER;
188 			/*logerror("taitosnd: Slave cpu sends 2/3 : %01x%01x\n",tc0140syt.masterdata[3],tc0140syt.masterdata[2]);*/
189 			cpu_spin(); /* writing should take longer than emulated, so spin */
190 			break;
191 
192 		case 0x04:		/* port status*/
193 			/*tc0140syt.status = TC0140SYT_SET_OK;*/
194 			/*logerror("tc0140syt : Slave cpu status ok.\n");*/
195 			break;
196 
197 		case 0x05:		/* nmi disable*/
198 			tc0140syt.nmi_enabled = 0;
199 			break;
200 
201 		case 0x06:		/* nmi enable*/
202 			tc0140syt.nmi_enabled = 1;
203 			break;
204 
205 		default:
206 			log_cb(RETRO_LOG_DEBUG, LOGPRE "tc0140syt: Slave cpu written in mode [%02x] data[%02x]\n",tc0140syt.submode, data & 0xff);
207 	}
208 
209 	Interrupt_Controller();
210 
211 }
212 
READ_HANDLER(taitosound_slave_comm_r)213 READ_HANDLER( taitosound_slave_comm_r )
214 {
215 	unsigned char res = 0;
216 
217 	switch ( tc0140syt.submode )
218 	{
219 		case 0x00:		/* mode #0*/
220 			/*logerror("taitosnd: Slave cpu read slavedata %01x\n", tc0140syt.slavedata[0]);*/
221 			res = tc0140syt.slavedata[tc0140syt.submode ++];
222 			break;
223 
224 		case 0x01:		/* mode #1*/
225 			/*logerror("taitosnd: Slave cpu receives 0/1 : %01x%01x PC=%4x\n", tc0140syt.slavedata[1],tc0140syt.slavedata[0],activecpu_get_pc());*/
226 			tc0140syt.status &= ~TC0140SYT_PORT01_FULL;
227 			res = tc0140syt.slavedata[tc0140syt.submode ++];
228 			break;
229 
230 		case 0x02:		/* mode #2*/
231 			/*logerror("taitosnd: Slave cpu read slavedata %01x\n", tc0140syt.slavedata[2]);*/
232 			res = tc0140syt.slavedata[tc0140syt.submode ++];
233 			break;
234 
235 		case 0x03:		/* mode #3*/
236 			/*logerror("taitosnd: Slave cpu receives 2/3 : %01x%01x\n", tc0140syt.slavedata[3],tc0140syt.slavedata[2]);*/
237 			tc0140syt.status &= ~TC0140SYT_PORT23_FULL;
238 			res = tc0140syt.slavedata[tc0140syt.submode ++];
239 			break;
240 
241 		case 0x04:		/* port status*/
242 			/*logerror("tc0140syt : Slave cpu read status : %02x\n", tc0140syt.status);*/
243 			res = tc0140syt.status;
244 			break;
245 
246 		default:
247 			log_cb(RETRO_LOG_DEBUG, LOGPRE "tc0140syt : Slave cpu read in mode [%02x]\n", tc0140syt.submode);
248 			res = 0;
249 	}
250 
251 	Interrupt_Controller();
252 
253     return res;
254 }
255 
256 
257 
258 
259 
260 
261 
262 /* wrapper functions for 16bit handlers */
263 
WRITE16_HANDLER(taitosound_port16_lsb_w)264 WRITE16_HANDLER( taitosound_port16_lsb_w )
265 {
266 	if (ACCESSING_LSB)
267 		taitosound_port_w(0,data & 0xff);
268 }
WRITE16_HANDLER(taitosound_comm16_lsb_w)269 WRITE16_HANDLER( taitosound_comm16_lsb_w )
270 {
271 	if (ACCESSING_LSB)
272 		taitosound_comm_w(0,data & 0xff);
273 }
READ16_HANDLER(taitosound_comm16_lsb_r)274 READ16_HANDLER( taitosound_comm16_lsb_r )
275 {
276 	return taitosound_comm_r(0);
277 }
278 
279 
WRITE16_HANDLER(taitosound_port16_msb_w)280 WRITE16_HANDLER( taitosound_port16_msb_w )
281 {
282 	if (ACCESSING_MSB)
283 		taitosound_port_w(0,data >> 8);
284 }
WRITE16_HANDLER(taitosound_comm16_msb_w)285 WRITE16_HANDLER( taitosound_comm16_msb_w )
286 {
287 	if (ACCESSING_MSB)
288 		taitosound_comm_w(0,data >> 8);
289 }
READ16_HANDLER(taitosound_comm16_msb_r)290 READ16_HANDLER( taitosound_comm16_msb_r )
291 {
292 	return taitosound_comm_r(0) << 8;
293 }
294