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