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