1 // Based on MAME driver by Curt Coder
2
3 #include "burnint.h"
4 #include "8255ppi.h"
5 #include <stddef.h>
6
7 #define MAX_PPIS 10
8
9 typedef struct
10 {
11 /* mode flags */
12 UINT8 groupA_mode;
13 UINT8 groupB_mode;
14 UINT8 portA_dir;
15 UINT8 portB_dir;
16 UINT8 portCH_dir;
17 UINT8 portCL_dir;
18
19 /* handshake signals (1=asserted; 0=non-asserted) */
20 UINT8 obf_a;
21 UINT8 obf_b;
22 UINT8 ibf_a;
23 UINT8 ibf_b;
24 UINT8 inte_a;
25 UINT8 inte_b;
26
27 UINT8 in_mask[3]; /* input mask */
28 UINT8 out_mask[3]; /* output mask */
29 UINT8 read[3]; /* data read from ports */
30 UINT8 latch[3]; /* data written to ports */
31 UINT8 output[3]; /* actual output data */
32
33 PPIPortRead PortRead[3];
34 PPIPortWrite PortWrite[3];
35 } ppi8255;
36
37 static ppi8255 chips[MAX_PPIS];
38 static INT32 nNumChips = 0;
39
ppi8255_get_handshake_signals(ppi8255 * chip,UINT8 * result)40 static void ppi8255_get_handshake_signals(ppi8255 *chip, UINT8 *result)
41 {
42 UINT8 handshake = 0x00;
43 UINT8 mask = 0x00;
44
45 /* group A */
46 if (chip->groupA_mode == 1)
47 {
48 if (chip->portA_dir)
49 {
50 handshake |= chip->ibf_a ? 0x20 : 0x00;
51 handshake |= (chip->ibf_a && chip->inte_a) ? 0x08 : 0x00;
52 mask |= 0x28;
53 }
54 else
55 {
56 handshake |= chip->obf_a ? 0x00 : 0x80;
57 handshake |= (chip->obf_a && chip->inte_a) ? 0x08 : 0x00;
58 mask |= 0x88;
59 }
60 }
61 else if (chip->groupA_mode == 2)
62 {
63 handshake |= chip->inte_a ? 0x08 : 0x00;
64 handshake |= chip->obf_a ? 0x00 : 0x80;
65 handshake |= chip->ibf_a ? 0x20 : 0x00;
66 mask |= 0xA8;
67 }
68
69 /* group B */
70 if (chip->groupB_mode == 1)
71 {
72 if (chip->portA_dir)
73 {
74 handshake |= chip->ibf_b ? 0x02 : 0x00;
75 handshake |= (chip->ibf_b && chip->inte_b) ? 0x01 : 0x00;
76 mask |= 0x03;
77 }
78 else
79 {
80 handshake |= chip->obf_b ? 0x00 : 0x02;
81 handshake |= (chip->obf_b && chip->inte_b) ? 0x01 : 0x00;
82 mask |= 0x03;
83 }
84 }
85
86 *result &= ~mask;
87 *result |= handshake & mask;
88 }
89
ppi8255_write_port(ppi8255 * chip,INT32 port,INT32 chipnum)90 static void ppi8255_write_port(ppi8255 *chip, INT32 port, INT32 chipnum)
91 {
92 UINT8 write_data;
93
94 write_data = chip->latch[port] & chip->out_mask[port];
95 write_data |= 0xFF & ~chip->out_mask[port];
96
97 /* write out special port 2 signals */
98 if (port == 2)
99 ppi8255_get_handshake_signals(chip, &write_data);
100
101 chip->output[port] = write_data;
102
103 if (chip->PortWrite[port]) chip->PortWrite[port](write_data);
104 }
105
ppi8255_input(ppi8255 * chip,INT32 port,UINT8 data,INT32 which)106 static void ppi8255_input(ppi8255 *chip, INT32 port, UINT8 data, INT32 which)
107 {
108 INT32 changed = 0;
109
110 chip->read[port] = data;
111
112 /* port C is special */
113 if (port == 2)
114 {
115 if (((chip->groupA_mode == 1) && (chip->portA_dir == 0)) || (chip->groupA_mode == 2))
116 {
117 /* is !ACKA asserted? */
118 if (chip->obf_a && !(data & 0x40))
119 {
120 chip->obf_a = 0;
121 changed = 1;
122 }
123 }
124
125 if ((chip->groupB_mode == 1) && (chip->portB_dir == 0))
126 {
127 /* is !ACKB asserted? */
128 if (chip->obf_b && !(data & 0x04))
129 {
130 chip->obf_b = 0;
131 changed = 1;
132 }
133 }
134
135 if (changed)
136 ppi8255_write_port(chip, 2, which);
137 }
138 }
139
ppi8255_read_port(ppi8255 * chip,INT32 port,INT32 chipnum)140 static UINT8 ppi8255_read_port(ppi8255 *chip, INT32 port, INT32 chipnum)
141 {
142 UINT8 result = 0x00;
143
144 if (chip->in_mask[port])
145 {
146 ppi8255_input(chip, port, (chip->PortRead[port]) ? chip->PortRead[port]() : 0, chipnum);
147
148 result |= chip->read[port] & chip->in_mask[port];
149 }
150 result |= chip->latch[port] & chip->out_mask[port];
151
152 /* read special port 2 signals */
153 if (port == 2)
154 ppi8255_get_handshake_signals(chip, &result);
155
156 return result;
157 }
158
ppi8255_set_read_port(INT32 which,INT32 port,PPIPortRead pr)159 void ppi8255_set_read_port(INT32 which, INT32 port, PPIPortRead pr)
160 {
161 #if defined FBNEO_DEBUG
162 if (!DebugDev_8255PPIInitted) bprintf(PRINT_ERROR, _T("ppi8255_set_read_port called without init\n"));
163 if (which > nNumChips) bprintf(PRINT_ERROR, _T("ppi8255_set_read_port called with invalid chip %x\n"), which);
164 #endif
165 ppi8255 *chip = &chips[which];
166
167 if (port >= 0xa && port <= 0xc) {
168 port -= 0xa;
169 }
170
171 chip->PortRead[port&3] = pr;
172 }
173
ppi8255_set_read_ports(INT32 which,PPIPortRead a,PPIPortRead b,PPIPortRead c)174 void ppi8255_set_read_ports(INT32 which, PPIPortRead a, PPIPortRead b, PPIPortRead c)
175 {
176 #if defined FBNEO_DEBUG
177 if (!DebugDev_8255PPIInitted) bprintf(PRINT_ERROR, _T("ppi8255_set_read_ports called without init\n"));
178 if (which > nNumChips) bprintf(PRINT_ERROR, _T("ppi8255_set_read_ports called with invalid chip %x\n"), which);
179 #endif
180 ppi8255 *chip = &chips[which];
181
182 chip->PortRead[0] = a;
183 chip->PortRead[1] = b;
184 chip->PortRead[2] = c;
185 }
186
ppi8255_set_write_port(INT32 which,INT32 port,PPIPortWrite pw)187 void ppi8255_set_write_port(INT32 which, INT32 port, PPIPortWrite pw)
188 {
189 #if defined FBNEO_DEBUG
190 if (!DebugDev_8255PPIInitted) bprintf(PRINT_ERROR, _T("ppi8255_set_write_port called without init\n"));
191 if (which > nNumChips) bprintf(PRINT_ERROR, _T("ppi8255_set_write_port called with invalid chip %x\n"), which);
192 #endif
193 ppi8255 *chip = &chips[which];
194
195 if (port >= 0xa && port <= 0xc) {
196 port -= 0xa;
197 }
198
199 chip->PortWrite[port&3] = pw;
200 }
201
ppi8255_set_write_ports(INT32 which,PPIPortWrite a,PPIPortWrite b,PPIPortWrite c)202 void ppi8255_set_write_ports(INT32 which, PPIPortWrite a, PPIPortWrite b, PPIPortWrite c)
203 {
204 #if defined FBNEO_DEBUG
205 if (!DebugDev_8255PPIInitted) bprintf(PRINT_ERROR, _T("ppi8255_set_write_ports called without init\n"));
206 if (which > nNumChips) bprintf(PRINT_ERROR, _T("ppi8255_set_write_ports called with invalid chip %x\n"), which);
207 #endif
208 ppi8255 *chip = &chips[which];
209
210 chip->PortWrite[0] = a;
211 chip->PortWrite[1] = b;
212 chip->PortWrite[2] = c;
213 }
214
ppi8255_r(INT32 which,INT32 offset)215 UINT8 ppi8255_r(INT32 which, INT32 offset)
216 {
217 #if defined FBNEO_DEBUG
218 if (!DebugDev_8255PPIInitted) bprintf(PRINT_ERROR, _T("ppi8255_r called without init\n"));
219 if (which > nNumChips) bprintf(PRINT_ERROR, _T("ppi8255_r called with invalid chip %x\n"), which);
220 #endif
221
222 ppi8255 *chip = &chips[which];
223 UINT8 result = 0;
224
225 offset %= 4;
226
227 switch(offset)
228 {
229 case 0: /* Port A read */
230 case 1: /* Port B read */
231 case 2: /* Port C read */
232 result = ppi8255_read_port(chip, offset, which);
233 break;
234
235 case 3: /* Control word */
236 result = 0xFF;
237 break;
238 }
239
240 return result;
241 }
242
set_mode(INT32 which,INT32 data,INT32 call_handlers)243 static void set_mode(INT32 which, INT32 data, INT32 call_handlers)
244 {
245 ppi8255 *chip = &chips[which];
246 INT32 i;
247
248 /* parse out mode */
249 chip->groupA_mode = (data >> 5) & 3;
250 chip->groupB_mode = (data >> 2) & 1;
251 chip->portA_dir = (data >> 4) & 1;
252 chip->portB_dir = (data >> 1) & 1;
253 chip->portCH_dir = (data >> 3) & 1;
254 chip->portCL_dir = (data >> 0) & 1;
255
256 /* normalize groupA_mode */
257 if (chip->groupA_mode == 3)
258 chip->groupA_mode = 2;
259
260 /* Port A direction */
261 if (chip->portA_dir)
262 chip->in_mask[0] = 0xFF, chip->out_mask[0] = 0x00; /* input */
263 else
264 chip->in_mask[0] = 0x00, chip->out_mask[0] = 0xFF; /* output */
265
266 /* Port B direction */
267 if (chip->portB_dir)
268 chip->in_mask[1] = 0xFF, chip->out_mask[1] = 0x00; /* input */
269 else
270 chip->in_mask[1] = 0x00, chip->out_mask[1] = 0xFF; /* output */
271
272 /* Port C upper direction */
273 if (chip->portCH_dir)
274 chip->in_mask[2] = 0xF0, chip->out_mask[2] = 0x00; /* input */
275 else
276 chip->in_mask[2] = 0x00, chip->out_mask[2] = 0xF0; /* output */
277
278 /* Port C lower direction */
279 if (chip->portCL_dir)
280 chip->in_mask[2] |= 0x0F; /* input */
281 else
282 chip->out_mask[2] |= 0x0F; /* output */
283
284 /* now depending on the group modes, certain Port C lines may be replaced
285 * with varying control signals */
286 switch(chip->groupA_mode)
287 {
288 case 0: /* Group A mode 0 */
289 /* no changes */
290 break;
291
292 case 1: /* Group A mode 1 */
293 /* bits 5-3 are reserved by Group A mode 1 */
294 chip->in_mask[2] &= ~0x38;
295 chip->out_mask[2] &= ~0x38;
296 break;
297
298 case 2: /* Group A mode 2 */
299 /* bits 7-3 are reserved by Group A mode 2 */
300 chip->in_mask[2] &= ~0xF8;
301 chip->out_mask[2] &= ~0xF8;
302 break;
303 }
304
305 switch(chip->groupB_mode)
306 {
307 case 0: /* Group B mode 0 */
308 /* no changes */
309 break;
310
311 case 1: /* Group B mode 1 */
312 /* bits 2-0 are reserved by Group B mode 1 */
313 chip->in_mask[2] &= ~0x07;
314 chip->out_mask[2] &= ~0x07;
315 break;
316 }
317
318 /* KT: 25-Dec-99 - 8255 resets latches when mode set */
319 chip->latch[0] = chip->latch[1] = chip->latch[2] = 0;
320
321 if (call_handlers)
322 {
323 for (i = 0; i < 3; i++)
324 ppi8255_write_port(chip, i, which);
325 }
326 }
327
ppi8255_w(INT32 which,INT32 offset,UINT8 data)328 void ppi8255_w(INT32 which, INT32 offset, UINT8 data)
329 {
330 #if defined FBNEO_DEBUG
331 if (!DebugDev_8255PPIInitted) bprintf(PRINT_ERROR, _T("ppi8255_w called without init\n"));
332 if (which > nNumChips) bprintf(PRINT_ERROR, _T("ppi8255_w called with invalid chip %x\n"), which);
333 #endif
334
335 ppi8255 *chip = &chips[which];
336
337 offset %= 4;
338
339 switch( offset )
340 {
341 case 0: /* Port A write */
342 case 1: /* Port B write */
343 case 2: /* Port C write */
344 chip->latch[offset] = data;
345 ppi8255_write_port(chip, offset, which);
346
347 switch(offset)
348 {
349 case 0:
350 if (!chip->portA_dir && (chip->groupA_mode != 0))
351 {
352 chip->obf_a = 1;
353 ppi8255_write_port(chip, 2, which);
354 }
355 break;
356
357 case 1:
358 if (!chip->portB_dir && (chip->groupB_mode != 0))
359 {
360 chip->obf_b = 1;
361 ppi8255_write_port(chip, 2, which);
362 }
363 break;
364 }
365 break;
366
367 case 3: /* Control word */
368 if (data & 0x80)
369 {
370 set_mode(which, data & 0x7f, 1);
371 }
372 else
373 {
374 /* bit set/reset */
375 INT32 bit;
376
377 bit = (data >> 1) & 0x07;
378
379 if (data & 1)
380 chip->latch[2] |= (1<<bit); /* set bit */
381 else
382 chip->latch[2] &= ~(1<<bit); /* reset bit */
383
384 ppi8255_write_port(chip, 2, which);
385 }
386 break;
387 }
388 }
389
ppi8255_reset()390 void ppi8255_reset()
391 {
392 for (INT32 i = 0; i < nNumChips; i++) {
393 ppi8255 *chip = &chips[i];
394
395 memset(chip, 0, STRUCT_SIZE_HELPER(ppi8255, output)); // clear everything but the handlers.
396
397 set_mode(i, 0x1b, 0);
398 }
399 }
400
ppi8255_init(INT32 num)401 void ppi8255_init(INT32 num)
402 {
403 DebugDev_8255PPIInitted = 1;
404
405 for (INT32 i = 0; i < num; i++) {
406 ppi8255 *chip = &chips[i];
407
408 memset(chip, 0, sizeof(*chip));
409
410 set_mode(i, 0x1b, 0);
411 }
412
413 nNumChips = num;
414 }
415
ppi8255_exit()416 void ppi8255_exit()
417 {
418 #if defined FBNEO_DEBUG
419 if (!DebugDev_8255PPIInitted) bprintf(PRINT_ERROR, _T("ppi8255_exit called without init\n"));
420 #endif
421
422 for (INT32 i = 0; i < MAX_PPIS; i++) {
423 ppi8255 *chip = &chips[i];
424
425 memset(chip, 0, sizeof(*chip));
426 }
427
428 DebugDev_8255PPIInitted = 0;
429 nNumChips = 0;
430 }
431
ppi8255_scan()432 void ppi8255_scan()
433 {
434 #if defined FBNEO_DEBUG
435 if (!DebugDev_8255PPIInitted) bprintf(PRINT_ERROR, _T("ppi8255_scan called without init\n"));
436 #endif
437
438 for (INT32 i = 0; i < nNumChips; i++) {
439 ScanVar(&chips[i], STRUCT_SIZE_HELPER(ppi8255, output), "ppi8255 Chip");
440 }
441 }
442
ppi8255_set_portC(INT32 which,UINT8 data)443 void ppi8255_set_portC( INT32 which, UINT8 data )
444 {
445 #if defined FBNEO_DEBUG
446 if (!DebugDev_8255PPIInitted) bprintf(PRINT_ERROR, _T("ppi8255_set_portC called without init\n"));
447 if (which > nNumChips) bprintf(PRINT_ERROR, _T("ppi8255_set_portC called with invalid chip %x\n"), which);
448 #endif
449
450 ppi8255_input(&chips[which], 2, data, which);
451 }
452
453 #undef MAX_PPIS
454