1  /**************************************************************************\
2  *						Microchip PIC16C5x Emulator							*
3  *																			*
4  *					  Copyright (C) 2003+ Tony La Porta						*
5  *				   Originally written for the MAME project.					*
6  *																			*
7  *																			*
8  *		Addressing architecture is based on the Harvard addressing scheme.	*
9  *																			*
10  *																			*
11  *	**** Change Log ****													*
12  *	TLP (06-Apr-2003)														*
13  *	 - First Public release.												*
14  *	BO  (07-Apr-2003) Ver 1.01  											*
15  *	 - Renamed 'sleep' function to 'sleepic' to avoid C conflicts.			*
16  *	TLP (09-Apr-2003) Ver 1.10  											*
17  *	 - Fixed modification of file register $03 (Status).					*
18  *	 - Corrected support for 7FFh (12-bit) size ROMs.						*
19  *	 - The 'call' and 'goto' instructions weren't correctly handling the	*
20  *	   STATUS page info correctly.											*
21  *	 - The FSR register was incorrectly oring the data with 0xe0 when read.	*
22  *	 - Prescaler masking information was set to 3 instead of 7.				*
23  *	 - Prescaler assign bit was set to 4 instead of 8.						*
24  *	 - Timer source and edge select flags/masks were wrong.					*
25  *	 - Corrected the memory bank selection in GET/SET_REGFILE and also the	*
26  *	   indirect register addressing.										*
27  *	BMP (18-May-2003) Ver 1.11												*
28  *	 - pic16c5x_get_reg functions were missing 'returns'.					*
29  *	TLP (27-May-2003) Ver 1.12  											*
30  *	 - Fixed the WatchDog timer count.										*
31  *	 - The Prescaler rate was incorrectly being zeroed, instead of the		*
32  *	   actual Prescaler counter in the CLRWDT and SLEEP instructions.		*
33  *	 - Added masking to the FSR register. Upper unused bits are always 1.	*
34  *																			*
35  *																			*
36  *	**** Notes: ****														*
37  *	PIC WatchDog Timer has a seperate internal clock. For the moment, we're	*
38  *	   basing the count on a 4MHz input clock, since 4MHz is the typical	*
39  *	   input frequency (but by no means always).							*
40  *	A single scaler is available for the Counter/Timer or WatchDog Timer.	*
41  *	   When connected to the Counter/Timer, it functions as a Prescaler,	*
42  *	   hence prescale overflows, tick the Counter/Timer.					*
43  *	   When connected to the WatchDog Timer, it functions as a Postscaler	*
44  *	   hence WatchDog Timer overflows, tick the Postscaler. This scenario	*
45  *	   means that the WatchDog timeout occurs when the Postscaler has		*
46  *	   reached the scaler rate value, not when the WatchDog reaches zero.	*
47  *	CLRWDT should prevent the WatchDog Timer from timing out and generating *
48  *	   a device reset, but how is not known. The manual also mentions that	*
49  *	   the WatchDog Timer can only be disabled during ROM programming, and	*
50  *	   no other means seem to exist???										*
51  *																			*
52  \**************************************************************************/
53 
54 
55 
56 #include <stdio.h>
57 #include <string.h>
58 #include <stdlib.h>
59 
60 #include <retro_inline.h>
61 
62 #include "driver.h"
63 #include "cpuintrf.h"
64 #include "mamedbg.h"
65 #include "state.h"
66 #include "pic16c5x.h"
67 
68 
69 #define CLK 1	/* 1 cycle equals 4 Q-clock ticks */
70 
71 
72 #define M_RDRAM(A)		PIC16C5x_RAM_RDMEM(A)
73 #define M_WRTRAM(A,V)	PIC16C5x_RAM_WRMEM(A,V)
74 #define M_RDOP(A)		PIC16C5x_RDOP(A)
75 #define M_RDOP_ARG(A)	PIC16C5x_RDOP_ARG(A)
76 #define P_IN(A)			PIC16C5x_In(A)
77 #define P_OUT(A,V)		PIC16C5x_Out(A,V)
78 #define S_T0_IN			PIC16C5x_T0_In
79 #define ADDR_MASK		0x7ff
80 
81 
82 
83 
84 typedef struct
85 {
86 	/******************** CPU Internal Registers *******************/
87 	UINT16	PC;
88 	UINT16	PREVPC;		/* previous program counter */
89 	UINT8	W;
90 	UINT8	OPTION;
91 	UINT16	CONFIG;
92 	UINT8	ALU;
93 	UINT16	WDT;
94 	UINT8	TRISA;
95 	UINT8	TRISB;
96 	UINT8	TRISC;
97 	UINT16	STACK[2];
98 	UINT16	prescaler;	/* Note: this is really an 8-bit register */
99 	PAIR	opcode;
100 	UINT8	*picRAM;
101 } pic16C5x_Regs;
102 
103 static pic16C5x_Regs R;
104 static UINT16 temp_config;
105 static UINT8  old_T0;
106 static INT8   old_data;
107 static UINT8 picRAMmask;
108 static int inst_cycles;
109 static int delay_timer;
110 static int picmodel;
111 static int pic16C5x_reset_vector;
112 int    pic16C5x_icount;
113 typedef void (*opcode_fn) (void);
114 static unsigned cycles_000_other[16];
115 
116 
117 #define TMR0	picRAM[1]
118 #define PCL		picRAM[2]
119 #define STATUS	picRAM[3]
120 #define FSR		picRAM[4]
121 #define PORTA	picRAM[5]
122 #define PORTB	picRAM[6]
123 #define PORTC	picRAM[7]
124 #define INDF	picRAM[(R.FSR)]
125 
126 #define ADDR	(R.opcode.b.l & 0x1f)
127 
128 #define POSITIVE_EDGE_T0  (( (int)(T0_in-old_T0) > 0) ? 1 : 0)
129 #define NEGATIVE_EDGE_T0  (( (int)(old_T0-T0_in) > 0) ? 1 : 0)
130 
131 
132 /********  The following is the Status Flag register definition.  *********/
133 			/* | 7 | 6 | 5 |  4 |  3 | 2 | 1  | 0 | */
134 			/* |    PA     | TO | PD | Z | DC | C | */
135 #define PA_REG		0xe0	/* PA	Program Page Preselect - bit 8 is unused here */
136 #define TO_FLAG		0x10	/* TO	Time Out flag (WatchDog) */
137 #define PD_FLAG		0x08	/* PD	Power Down flag */
138 #define Z_FLAG		0x04	/* Z	Zero Flag */
139 #define DC_FLAG		0x02	/* DC	Digit Carry/Borrow flag (Nibble) */
140 #define C_FLAG		0x01	/* C    Carry/Borrow Flag (Byte) */
141 
142 #define PA		(R.STATUS & PA_REG)
143 #define TO		(R.STATUS & TO_FLAG)
144 #define PD		(R.STATUS & PD_FLAG)
145 #define ZERO	(R.STATUS & Z_FLAG)
146 #define DC		(R.STATUS & DC_FLAG)
147 #define CARRY	(R.STATUS & C_FLAG)
148 
149 
150 /********  The following is the Option Flag register definition.  *********/
151 			/* | 7 | 6 |   5  |   4  |  3  | 2 | 1 | 0 | */
152 			/* | 0 | 0 | TOCS | TOSE | PSA |    PS     | */
153 #define T0CS_FLAG	0x20	/* TOCS		Timer 0 clock source select */
154 #define T0SE_FLAG	0x10	/* TOSE		Timer 0 clock source edge select */
155 #define PSA_FLAG	0x08	/* PSA		Prescaler Assignment bit */
156 #define PS_REG		0x07	/* PS		Prescaler Rate select */
157 
158 #define T0CS	(R.OPTION & T0CS_FLAG)
159 #define T0SE	(R.OPTION & T0SE_FLAG)
160 #define PSA		(R.OPTION & PSA_FLAG)
161 #define PS		(R.OPTION & PS_REG)
162 
163 
164 /********  The following is the Config Flag register definition.  *********/
165 	/* | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 |   2  | 1 | 0 | */
166 	/* |              CP                     | WDTE |  FOSC | */
167 							/* CP		Code Protect (ROM read protect) */
168 #define WDTE_FLAG	0x04	/* WDTE		WatchDog Timer enable */
169 #define FOSC_FLAG	0x03	/* FOSC		Oscillator source select */
170 
171 #define WDTE	(R.CONFIG & WDTE_FLAG)
172 #define FOSC	(R.CONFIG & FOSC_FLAG)
173 
174 
175 /************************************************************************
176  *	Shortcuts
177  ************************************************************************/
178 
179 /* Easy bit position selectors */
180 #define POS	 ((R.opcode.b.l >> 5) & 7)
181 static unsigned int bit_clr[8] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f };
182 static unsigned int bit_set[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
183 
184 
CLR(UINT16 flag)185 static INLINE void CLR(UINT16 flag) { R.STATUS &= ~flag; }
SET(UINT16 flag)186 static INLINE void SET(UINT16 flag) { R.STATUS |=  flag; }
187 
188 
189 
CALCULATE_Z_FLAG(void)190 static INLINE void CALCULATE_Z_FLAG(void)
191 {
192 	if (R.ALU == 0) SET(Z_FLAG);
193 	else CLR(Z_FLAG);
194 }
195 
CALCULATE_ADD_CARRY(void)196 static INLINE void CALCULATE_ADD_CARRY(void)
197 {
198 	if ((UINT8)(old_data) > (UINT8)(R.ALU)) {
199 		SET(C_FLAG);
200 	}
201 	else {
202 		CLR(C_FLAG);
203 	}
204 }
205 
CALCULATE_ADD_DIGITCARRY(void)206 static INLINE void CALCULATE_ADD_DIGITCARRY(void)
207 {
208 	if (((UINT8)(old_data) & 0x0f) > ((UINT8)(R.ALU) & 0x0f)) {
209 		SET(DC_FLAG);
210 	}
211 	else {
212 		CLR(DC_FLAG);
213 	}
214 }
215 
CALCULATE_SUB_CARRY(void)216 static INLINE void CALCULATE_SUB_CARRY(void)
217 {
218 	if ((UINT8)(old_data) < (UINT8)(R.ALU)) {
219 		CLR(C_FLAG);
220 	}
221 	else {
222 		SET(C_FLAG);
223 	}
224 }
225 
CALCULATE_SUB_DIGITCARRY(void)226 static INLINE void CALCULATE_SUB_DIGITCARRY(void)
227 {
228 	if (((UINT8)(old_data) & 0x0f) < ((UINT8)(R.ALU) & 0x0f)) {
229 		CLR(DC_FLAG);
230 	}
231 	else {
232 		SET(DC_FLAG);
233 	}
234 }
235 
236 
237 
POP_STACK(void)238 static INLINE UINT16 POP_STACK(void)
239 {
240 	UINT16 data = R.STACK[1];
241 	R.STACK[1] = R.STACK[0];
242 	return (data & ADDR_MASK);
243 }
PUSH_STACK(UINT16 data)244 static INLINE void PUSH_STACK(UINT16 data)
245 {
246 	R.STACK[0] = R.STACK[1];
247 	R.STACK[1] = (data & ADDR_MASK);
248 }
249 
250 
GET_REGFILE(offs_t addr)251 static INLINE UINT8 GET_REGFILE(offs_t addr)	/* Read from internal memory */
252 {
253 	UINT8 data;
254 
255 	if ((picmodel == 0x16C57) || (picmodel == 0x16C58))
256 	{
257 		addr |= (R.FSR & 0x60);		/* FSR used for banking */
258 	}
259 	if ((addr & 0x10) == 0) addr &= 0x0f;
260 
261 	switch(addr)
262 	{
263 		case 00:	addr = (R.FSR & picRAMmask);
264 					if (addr == 0) { data = 0; break; }
265 					if ((addr & 0x10) == 0) addr &= 0x0f;
266 					data = R.picRAM[addr];			/* Indirect address */
267 					break;
268 		case 04:	data = (R.FSR | (~picRAMmask)); break;
269 		case 05:	data = P_IN(0);
270 					data &= R.TRISA;
271 					data |= (~R.TRISA & R.PORTA);
272 					data &= 0xf;		/* 4-bit port (only lower 4 bits used) */
273 					break;
274 		case 06:	data = P_IN(1);
275 					data &= R.TRISB;
276 					data |= (~R.TRISB & R.PORTB);
277 					break;
278 		case 07:	if ((picmodel == 0x16C55) || (picmodel == 0x16C57)) {
279 						data = P_IN(2);
280 						data &= R.TRISC;
281 						data |= (~R.TRISC & R.PORTC);
282 					}
283 					else {		/* PIC16C54, PIC16C56, PIC16C58 */
284 						data = R.picRAM[addr];
285 					}
286 					break;
287 		default:	data = R.picRAM[addr]; break;
288 	}
289 
290 	return data;
291 }
292 
STORE_REGFILE(offs_t addr,UINT8 data)293 static INLINE void STORE_REGFILE(offs_t addr, UINT8 data)	/* Write to internal memory */
294 {
295 	if ((picmodel == 0x16C57) || (picmodel == 0x16C58))
296 	{
297 		addr |= (R.FSR & 0x60);
298 	}
299 	if ((addr & 0x10) == 0) addr &= 0x0f;
300 
301 	switch(addr)
302 	{
303 		case 00:	addr = (R.FSR & picRAMmask);
304 					if (addr == 0) break;
305 					if ((addr & 0x10) == 0) addr &= 0x0f;
306 					R.picRAM[addr] = data; break;	/* Indirect address */
307 		case 01:	delay_timer = 2;		/* Timer starts after next two instructions */
308 					if (PSA == 0) R.prescaler = 0;	/* Must clear the Prescaler */
309 					R.TMR0 = data; break;
310 		case 02:	R.PCL = data;
311 					R.PC = ((R.STATUS & PA_REG) << 4) | data; break;
312 		case 03:	R.STATUS &= ~PA_REG; R.STATUS |= (data & PA_REG); break;
313 		case 04:	R.FSR = (data | (~picRAMmask)); break;
314 		case 05:	data &= 0xf;		/* 4-bit port (only lower 4 bits used) */
315 					P_OUT(0,data & (~R.TRISA)); R.PORTA = data; break;
316 		case 06:	P_OUT(1,data & (~R.TRISB)); R.PORTB = data; break;
317 		case 07:	if ((picmodel == 0x16C55) || (picmodel == 0x16C57)) {
318 						P_OUT(2,data & (~R.TRISC));
319 						R.PORTC = data;
320 					}
321 					else {		/* PIC16C54, PIC16C56, PIC16C58 */
322 						R.picRAM[addr] = data;
323 					}
324 					break;
325 		default:	R.picRAM[addr] = data; break;
326 	}
327 }
328 
329 
STORE_RESULT(offs_t addr,UINT8 data)330 static INLINE void STORE_RESULT(offs_t addr, UINT8 data)
331 {
332 	if (R.opcode.b.l & 0x20)
333 	{
334 		STORE_REGFILE(addr, data);
335 	}
336 	else
337 	{
338 		R.W = data;
339 	}
340 }
341 
342 
343 /************************************************************************
344  *	Emulate the Instructions
345  ************************************************************************/
346 
347 /* This following function is here to fill in the void for */
348 /* the opcode call function. This function is never called. */
349 
350 
illegal(void)351 static void illegal(void)
352 {
353 	log_cb(RETRO_LOG_DEBUG, LOGPRE "PIC16C5x:  PC=%03x,  Illegal opcode = %04x\n", (R.PC-1), R.opcode.w.l);
354 }
355 
356 
addwf(void)357 static void addwf(void)
358 {
359 	old_data = GET_REGFILE(ADDR);
360 	R.ALU = old_data + R.W;
361 	STORE_RESULT(ADDR, R.ALU);
362 	CALCULATE_Z_FLAG();
363 	CALCULATE_ADD_CARRY();
364 	CALCULATE_ADD_DIGITCARRY();
365 }
366 
andwf(void)367 static void andwf(void)
368 {
369 	R.ALU = GET_REGFILE(ADDR) & R.W;
370 	STORE_RESULT(ADDR, R.ALU);
371 	CALCULATE_Z_FLAG();
372 }
373 
andlw(void)374 static void andlw(void)
375 {
376 	R.ALU = R.opcode.b.l & R.W;
377 	R.W = R.ALU;
378 	CALCULATE_Z_FLAG();
379 }
380 
bcf(void)381 static void bcf(void)
382 {
383 	R.ALU = GET_REGFILE(ADDR);
384 	R.ALU &= bit_clr[POS];
385 	STORE_REGFILE(ADDR, R.ALU);
386 }
387 
bsf(void)388 static void bsf(void)
389 {
390 	R.ALU = GET_REGFILE(ADDR);
391 	R.ALU |= bit_set[POS];
392 	STORE_REGFILE(ADDR, R.ALU);
393 }
394 
btfss(void)395 static void btfss(void)
396 {
397 	if ((GET_REGFILE(ADDR) & bit_set[POS]) == bit_set[POS])
398 	{
399 		R.PC++ ;
400 		R.PCL = R.PC & 0xff;
401 		inst_cycles += cycles_000_other[0];		/* Add NOP cycles */
402 	}
403 }
404 
btfsc(void)405 static void btfsc(void)
406 {
407 	if ((GET_REGFILE(ADDR) & bit_set[POS]) == 0)
408 	{
409 		R.PC++ ;
410 		R.PCL = R.PC & 0xff;
411 		inst_cycles += cycles_000_other[0];		/* Add NOP cycles */
412 	}
413 }
414 
call(void)415 static void call(void)
416 {
417 	PUSH_STACK(R.PC);
418 	R.PC = ((R.STATUS & PA_REG) << 4) | R.opcode.b.l;
419 	R.PC &= 0x6ff;
420 	R.PCL = R.PC & 0xff;
421 }
422 
clrw(void)423 static void clrw(void)
424 {
425 	R.W = 0;
426 	SET(Z_FLAG);
427 }
428 
clrf(void)429 static void clrf(void)
430 {
431 	STORE_REGFILE(ADDR, 0);
432 	SET(Z_FLAG);
433 }
434 
clrwdt(void)435 static void clrwdt(void)
436 {
437 	R.WDT = 0;
438 	if (PSA) R.prescaler = 0;
439 	SET(TO_FLAG);
440 	SET(PD_FLAG);
441 }
442 
comf(void)443 static void comf(void)
444 {
445 	R.ALU = ~(GET_REGFILE(ADDR));
446 	STORE_RESULT(ADDR, R.ALU);
447 	CALCULATE_Z_FLAG();
448 }
449 
decf(void)450 static void decf(void)
451 {
452 	R.ALU = GET_REGFILE(ADDR) - 1;
453 	STORE_RESULT(ADDR, R.ALU);
454 	CALCULATE_Z_FLAG();
455 }
456 
decfsz(void)457 static void decfsz(void)
458 {
459 	R.ALU = GET_REGFILE(ADDR) - 1;
460 	STORE_RESULT(ADDR, R.ALU);
461 	if (R.ALU == 0)
462 	{
463 		R.PC++ ;
464 		R.PCL = R.PC & 0xff;
465 		inst_cycles += cycles_000_other[0];		/* Add NOP cycles */
466 	}
467 }
468 
goto_op(void)469 static void goto_op(void)
470 {
471 	R.PC = ((R.STATUS & PA_REG) << 4) | (R.opcode.w.l & 0x1ff);
472 	R.PC &= ADDR_MASK;
473 	R.PCL = R.PC & 0xff;
474 }
475 
incf(void)476 static void incf(void)
477 {
478 	R.ALU = GET_REGFILE(ADDR) + 1;
479 	STORE_RESULT(ADDR, R.ALU);
480 	CALCULATE_Z_FLAG();
481 }
482 
incfsz(void)483 static void incfsz(void)
484 {
485 	R.ALU = GET_REGFILE(ADDR) + 1;
486 	STORE_RESULT(ADDR, R.ALU);
487 	if (R.ALU == 0)
488 	{
489 		R.PC++ ;
490 		R.PCL = R.PC & 0xff;
491 		inst_cycles += cycles_000_other[0];		/* Add NOP cycles */
492 	}
493 }
494 
iorlw(void)495 static void iorlw(void)
496 {
497 	R.ALU = R.opcode.b.l | R.W;
498 	STORE_RESULT(ADDR, R.ALU);
499 	CALCULATE_Z_FLAG();
500 }
501 
iorwf(void)502 static void iorwf(void)
503 {
504 	R.ALU = GET_REGFILE(ADDR) | R.W;
505 	STORE_RESULT(ADDR, R.ALU);
506 	CALCULATE_Z_FLAG();
507 }
508 
movf(void)509 static void movf(void)
510 {
511 	R.ALU = GET_REGFILE(ADDR);
512 	STORE_RESULT(ADDR, R.ALU);
513 	CALCULATE_Z_FLAG();
514 }
515 
movlw(void)516 static void movlw(void)
517 {
518 	R.W = R.opcode.b.l;
519 }
520 
movwf(void)521 static void movwf(void)
522 {
523 	STORE_REGFILE(ADDR, R.W);
524 }
525 
nop(void)526 static void nop(void)
527 {
528 	/* Do nothing */
529 }
530 
option(void)531 static void option(void)
532 {
533 	R.OPTION = R.W & 0x3f;
534 }
535 
retlw(void)536 static void retlw(void)
537 {
538 	R.W = R.opcode.b.l;
539 	R.PC = POP_STACK();
540 	R.PCL = R.PC & 0xff;
541 }
542 
rlf(void)543 static void rlf(void)
544 {
545 	R.ALU = GET_REGFILE(ADDR);
546 	R.ALU <<= 1;
547 	if (R.STATUS & C_FLAG) R.ALU |= 1;
548 	if (GET_REGFILE(ADDR) & 0x80) SET(C_FLAG);
549 	else CLR(C_FLAG);
550 	STORE_RESULT(ADDR, R.ALU);
551 }
552 
rrf(void)553 static void rrf(void)
554 {
555 	R.ALU = GET_REGFILE(ADDR);
556 	R.ALU >>= 1;
557 	if (R.STATUS & C_FLAG) R.ALU |= 0x80;
558 	if (GET_REGFILE(ADDR) & 1) SET(C_FLAG);
559 	else CLR(C_FLAG);
560 	STORE_RESULT(ADDR, R.ALU);
561 }
562 
sleepic(void)563 static void sleepic(void)
564 {
565 	if (WDTE) R.WDT = 0;
566 	if (PSA) R.prescaler = 0;
567 	SET(TO_FLAG);
568 	CLR(PD_FLAG);
569 }
570 
subwf(void)571 static void subwf(void)
572 {
573 	old_data = GET_REGFILE(ADDR);
574 	R.ALU = old_data - R.W;
575 	STORE_RESULT(ADDR, R.ALU);
576 	CALCULATE_Z_FLAG();
577 	CALCULATE_SUB_CARRY();
578 	CALCULATE_SUB_DIGITCARRY();
579 }
580 
swapf(void)581 static void swapf(void)
582 {
583 	R.ALU  = ((GET_REGFILE(ADDR) << 4) & 0xf0);
584 	R.ALU |= ((GET_REGFILE(ADDR) >> 4) & 0x0f);
585 	STORE_RESULT(ADDR, R.ALU);
586 }
587 
tris(void)588 static void tris(void)
589 {
590 	switch(R.opcode.b.l & 0x7)
591 	{
592 		case 05:	if (R.TRISA == R.W) break;
593 					else R.TRISA = R.W; P_OUT(0,R.PORTA & (~R.TRISA) & 0xf); break;
594 		case 06:	if (R.TRISB == R.W) break;
595 					else R.TRISB = R.W; P_OUT(1,R.PORTB & (~R.TRISB)); break;
596 		case 07:	if (R.TRISC == R.W) break;
597 					else R.TRISC = R.W; P_OUT(2,R.PORTC & (~R.TRISC)); break;
598 		default:	illegal(); break;
599 	}
600 }
601 
xorlw(void)602 static void xorlw(void)
603 {
604 	R.ALU = R.W ^ R.opcode.b.l;
605 	R.W = R.ALU;
606 	CALCULATE_Z_FLAG();
607 }
608 
xorwf(void)609 static void xorwf(void)
610 {
611 	R.ALU = GET_REGFILE(ADDR) ^ R.W;
612 	STORE_RESULT(ADDR, R.ALU);
613 	CALCULATE_Z_FLAG();
614 }
615 
616 
617 
618 /***********************************************************************
619  *	Cycle Timings
620  ***********************************************************************/
621 
622 static unsigned cycles_main[256]=
623 {
624 /*00*/	1*CLK, 0*CLK, 1*CLK, 1*CLK, 1*CLK, 0*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
625 /*10*/	1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
626 /*20*/	1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
627 /*30*/	1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
628 /*40*/	1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
629 /*50*/	1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
630 /*60*/	1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
631 /*70*/	1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
632 /*80*/	2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK,
633 /*90*/	2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK,
634 /*A0*/	2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK,
635 /*B0*/	2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK, 2*CLK,
636 /*C0*/	1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
637 /*D0*/	1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
638 /*E0*/	1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK,
639 /*F0*/	1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK
640 };
641 
642 static opcode_fn opcode_main[256]=
643 {
644 /*00*/  nop,	illegal,movwf,	movwf,	clrw,	illegal,clrf,	clrf,
645 /*08*/  subwf,	subwf,	subwf,	subwf,	decf,	decf,	decf,	decf,
646 /*10*/  iorwf,	iorwf,	iorwf,	iorwf,	andwf,	andwf,	andwf,	andwf,
647 /*18*/  xorwf,	xorwf,	xorwf,	xorwf,	addwf,	addwf,	addwf,	addwf,
648 /*20*/  movf,	movf,	movf,	movf,	comf,	comf,	comf,	comf,
649 /*28*/  incf,	incf,	incf,	incf,	decfsz,	decfsz,	decfsz,	decfsz,
650 /*30*/  rrf,	rrf,	rrf,	rrf,	rlf,	rlf,	rlf,	rlf,
651 /*38*/  swapf,	swapf,	swapf,	swapf,	incfsz,	incfsz,	incfsz,	incfsz,
652 /*40*/  bcf,	bcf,	bcf,	bcf,	bcf,	bcf,	bcf,	bcf,
653 /*48*/  bcf,	bcf,	bcf,	bcf,	bcf,	bcf,	bcf,	bcf,
654 /*50*/  bsf,	bsf,	bsf,	bsf,	bsf,	bsf,	bsf,	bsf,
655 /*58*/  bsf,	bsf,	bsf,	bsf,	bsf,	bsf,	bsf,	bsf,
656 /*60*/  btfsc,	btfsc,	btfsc,	btfsc,	btfsc,	btfsc,	btfsc,	btfsc,
657 /*68*/  btfsc,	btfsc,	btfsc,	btfsc,	btfsc,	btfsc,	btfsc,	btfsc,
658 /*70*/  btfss,	btfss,	btfss,	btfss,	btfss,	btfss,	btfss,	btfss,
659 /*78*/  btfss,	btfss,	btfss,	btfss,	btfss,	btfss,	btfss,	btfss,
660 /*80*/  retlw,	retlw,	retlw,	retlw,	retlw,	retlw,	retlw,	retlw,
661 /*88*/  retlw,	retlw,	retlw,	retlw,	retlw,	retlw,	retlw,	retlw,
662 /*90*/  call,	call,	call,	call,	call,	call,	call,	call,
663 /*98*/  call,	call,	call,	call,	call,	call,	call,	call,
664 /*A0*/  goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,
665 /*A8*/  goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,
666 /*B0*/  goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,
667 /*B8*/  goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,
668 /*C0*/  movlw,	movlw,	movlw,	movlw,	movlw,	movlw,	movlw,	movlw,
669 /*C8*/  movlw,	movlw,	movlw,	movlw,	movlw,	movlw,	movlw,	movlw,
670 /*D0*/  iorlw,	iorlw,	iorlw,	iorlw,	iorlw,	iorlw,	iorlw,	iorlw,
671 /*D8*/  iorlw,	iorlw,	iorlw,	iorlw,	iorlw,	iorlw,	iorlw,	iorlw,
672 /*E0*/  andlw,	andlw,	andlw,	andlw,	andlw,	andlw,	andlw,	andlw,
673 /*E8*/  andlw,	andlw,	andlw,	andlw,	andlw,	andlw,	andlw,	andlw,
674 /*F0*/  xorlw,	xorlw,	xorlw,	xorlw,	xorlw,	xorlw,	xorlw,	xorlw,
675 /*F8*/  xorlw,	xorlw,	xorlw,	xorlw,	xorlw,	xorlw,	xorlw,	xorlw
676 };
677 
678 
679 static unsigned cycles_000_other[16]=
680 {
681 /*00*/	1*CLK, 0*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 1*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK, 0*CLK
682 };
683 
684 static opcode_fn opcode_000_other[16]=
685 {
686 /*00*/  nop,	illegal,option,	sleepic,clrwdt,	tris,	tris,	tris,
687 /*08*/  illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal
688 };
689 
690 
691 
692 /****************************************************************************
693  *	Inits CPU emulation
694  ****************************************************************************/
695 
pic16C5x_init(void)696 void pic16C5x_init(void)
697 {
698 	int cpu = cpu_getactivecpu();
699 
700 	state_save_register_INT8("pic16C5x", cpu, "Old_Data", &old_data, 1);
701 	state_save_register_UINT8("pic16C5x", cpu, "W", &R.W, 1);
702 	state_save_register_UINT8("pic16C5x", cpu, "ALU", &R.ALU, 1);
703 	state_save_register_UINT8("pic16C5x", cpu, "Option", &R.OPTION, 1);
704 	state_save_register_UINT8("pic16C5x", cpu, "TRISA", &R.TRISA, 1);
705 	state_save_register_UINT8("pic16C5x", cpu, "TRISB", &R.TRISB, 1);
706 	state_save_register_UINT8("pic16C5x", cpu, "TRISC", &R.TRISC, 1);
707 	state_save_register_UINT8("pic16C5x", cpu, "PORTA", &R.PORTA, 1);
708 	state_save_register_UINT8("pic16C5x", cpu, "PORTB", &R.PORTB, 1);
709 	state_save_register_UINT8("pic16C5x", cpu, "PORTC", &R.PORTC, 1);
710 	state_save_register_UINT8("pic16C5x", cpu, "Old_T0", &old_T0, 1);
711 	state_save_register_UINT8("pic16C5x", cpu, "STR", &R.STATUS, 1);
712 	state_save_register_UINT8("pic16C5x", cpu, "RAM_mask", &picRAMmask, 1);
713 	state_save_register_UINT16("pic16C5x", cpu, "WDT", &R.WDT, 1);
714 	state_save_register_UINT16("pic16C5x", cpu, "Prescaler", &R.prescaler, 1);
715 	state_save_register_UINT16("pic16C5x", cpu, "Stack0", &R.STACK[0], 1);
716 	state_save_register_UINT16("pic16C5x", cpu, "Stack1", &R.STACK[1], 1);
717 	state_save_register_UINT16("pic16C5x", cpu, "PC", &R.PC, 1);
718 	state_save_register_UINT16("pic16C5x", cpu, "PrevPC", &R.PREVPC, 1);
719 	state_save_register_UINT16("pic16C5x", cpu, "Config", &R.CONFIG, 1);
720 	state_save_register_UINT32("pic16C5x", cpu, "Opcode", &R.opcode.d, 1);
721 	state_save_register_INT32("pic16C5x", cpu, "Delay_Timer", &delay_timer, 1);
722 	state_save_register_INT32("pic16C5x", cpu, "PIC_model", &picmodel, 1);
723 	state_save_register_INT32("pic16C5x", cpu, "Reset_Vector", &pic16C5x_reset_vector, 1);
724 }
725 
726 
727 /****************************************************************************
728  *	Reset registers to their initial values
729  ****************************************************************************/
730 
pic16C5x_reset_regs(void)731 void pic16C5x_reset_regs(void)
732 {
733 	/* ugly hack.. */
734 	R.picRAM = memory_region(REGION_CPU1 + cpu_getactivecpu());
735 
736 	R.PC     = pic16C5x_reset_vector;
737 	R.CONFIG = temp_config;
738 	R.TRISA  = 0xff;
739 	R.TRISB  = 0xff;
740 	R.TRISC  = 0xff;
741 	R.OPTION = 0x3f;
742 	R.PCL    = 0xff;
743 	R.FSR   |= (~picRAMmask);
744 	R.PORTA &= 0x0f;
745 	R.prescaler = 0;
746 	delay_timer = 0;
747 	old_T0      = 0;
748 	inst_cycles = 0;
749 }
750 
pic16C5x_soft_reset(void)751 void pic16C5x_soft_reset(void)
752 {
753 	R.STATUS &= 0x1f;
754 	pic16C5x_reset_regs();
755 }
756 
pic16c5x_config(int data)757 void pic16c5x_config(int data)
758 {
759 	log_cb(RETRO_LOG_DEBUG, LOGPRE "Writing %04x to the PIC16C5x config register\n",data);
760 	temp_config = (data & 0xfff);
761 }
762 
763 
764 /****************************************************************************
765  *	Shut down CPU emulation
766  ****************************************************************************/
767 
pic16C5x_exit(void)768 void pic16C5x_exit (void)
769 {
770 	/* nothing to do */
771 }
772 
773 
774 /****************************************************************************
775  *	WatchDog
776  ****************************************************************************/
777 
pic16C5x_update_watchdog(int counts)778 static void pic16C5x_update_watchdog(int counts)
779 {
780 	/* WatchDog is set up to count 18,000 (0x464f hex) ticks to provide */
781 	/* the timeout period of 0.018ms based on a 4MHz input clock. */
782 	/* Note: the 4MHz clock should be divided by the PIC16C5x_CLOCK_DIVIDER */
783 	/* which effectively makes the PIC run at 1MHz internally. */
784 
785 	/* If the current instruction is CLRWDT or SLEEP, don't update the WDT */
786 
787 	if ((R.opcode.w.l != 3) && (R.opcode.w.l != 4))
788 	{
789 		UINT16 old_WDT = R.WDT;
790 
791 		R.WDT -= counts;
792 
793 		if (R.WDT > 0x464f) {
794 			R.WDT = 0x464f - (0xffff - R.WDT);
795 		}
796 
797 		if (((old_WDT != 0) && (old_WDT < R.WDT)) || (R.WDT == 0))
798 		{
799 			if (PSA) {
800 				R.prescaler++;
801 				if (R.prescaler >= (1 << PS)) {	/* Prescale values from 1 to 128 */
802 					R.prescaler = 0;
803 					CLR(TO_FLAG);
804 					pic16C5x_soft_reset();
805 				}
806 			}
807 			else {
808 				CLR(TO_FLAG);
809 				pic16C5x_soft_reset();
810 			}
811 		}
812 	}
813 }
814 
815 
816 /****************************************************************************
817  *	Update Timer
818  ****************************************************************************/
819 
pic16C5x_update_timer(int counts)820 static void pic16C5x_update_timer(int counts)
821 {
822 	if (PSA == 0) {
823 		R.prescaler += counts;
824 		if (R.prescaler >= (2 << PS)) {	/* Prescale values from 2 to 256 */
825 			R.TMR0 += (R.prescaler / (2 << PS));
826 			R.prescaler %= (2 << PS);	/* Overflow prescaler */
827 		}
828 	}
829 	else {
830 		R.TMR0 += counts;
831 	}
832 }
833 
834 
835 /****************************************************************************
836  *	Execute IPeriod. Return 0 if emulation should be stopped
837  ****************************************************************************/
838 
pic16C5x_execute(int cycles)839 int pic16C5x_execute(int cycles)
840 {
841 	int T0_in;
842 	pic16C5x_icount = cycles;
843 
844 	do
845 	{
846 		if (PD == 0)						/* Sleep Mode */
847 		{
848 			inst_cycles = (1*CLK);
849 			CALL_MAME_DEBUG;
850 			if (WDTE) {
851 				pic16C5x_update_watchdog(1*CLK);
852 			}
853 		}
854 		else
855 		{
856 			R.PREVPC = R.PC;
857 
858 			CALL_MAME_DEBUG;
859 
860 			R.opcode.d = M_RDOP(R.PC);
861 			R.PC++;
862 			R.PCL++;
863 
864 			if ((R.opcode.w.l & 0xff0) != 0x000)	{	/* Do all opcodes except the 00? ones */
865 				inst_cycles = cycles_main[((R.opcode.w.l >> 4) & 0xff)];
866 				(*(opcode_main[((R.opcode.w.l >> 4) & 0xff)]))();
867 			}
868 			else {	/* Opcode 0x00? has many opcodes in its minor nibble */
869 				inst_cycles = cycles_000_other[(R.opcode.b.l & 0x1f)];
870 				(*(opcode_000_other[(R.opcode.b.l & 0x1f)]))();
871 			}
872 
873 			if (T0CS) {						/* Count mode */
874 				T0_in = S_T0_IN;
875 				if (T0SE) {					/* Count rising edge */
876 					if (POSITIVE_EDGE_T0) {
877 						pic16C5x_update_timer(1);
878 					}
879 				}
880 				else {						/* Count falling edge */
881 					if (NEGATIVE_EDGE_T0) {
882 						pic16C5x_update_timer(1);
883 					}
884 				}
885 				old_T0 = T0_in;
886 			}
887 			else {							/* Timer mode */
888 				if (delay_timer) {
889 					delay_timer--;
890 				}
891 				else {
892 					pic16C5x_update_timer((inst_cycles/CLK));
893 				}
894 			}
895 			if (WDTE) {
896 				pic16C5x_update_watchdog((inst_cycles/CLK));
897 			}
898 		}
899 
900 		pic16C5x_icount -= inst_cycles;
901 
902 	} while (pic16C5x_icount>0);
903 
904 	return cycles - pic16C5x_icount;
905 }
906 
907 
908 /****************************************************************************
909  *	Get all registers in given buffer
910  ****************************************************************************/
911 
pic16C5x_get_context(void * dst)912 unsigned pic16C5x_get_context (void *dst)
913 {
914 	if( dst )
915 		*(pic16C5x_Regs*)dst = R;
916 	return sizeof(pic16C5x_Regs);
917 }
918 
919 
920 /****************************************************************************
921  *	Set all registers to given values
922  ****************************************************************************/
923 
pic16C5x_set_context(void * src)924 void pic16C5x_set_context (void *src)
925 {
926 	if (src)
927 		R = *(pic16C5x_Regs*)src;
928 }
929 
930 
931 /****************************************************************************
932  *	Return a specific register
933  ****************************************************************************/
934 
pic16C5x_get_reg(int regnum)935 unsigned pic16C5x_get_reg(int regnum)
936 {
937 	switch (regnum)
938 	{
939 		case REG_PC:
940 		case PIC16C5x_PC: return R.PC;
941 		case REG_PREVIOUSPC: return R.PREVPC;
942 		/* This is actually not a stack pointer, but the stack contents */
943 		case REG_SP:
944 		case PIC16C5x_STK1: return R.STACK[1];
945 		case PIC16C5x_STK0: return R.STACK[0];
946 		case PIC16C5x_W:    return R.W;
947 		case PIC16C5x_ALU:  return R.ALU;
948 		case PIC16C5x_STR:  return R.STATUS;
949 		case PIC16C5x_OPT:  return R.OPTION;
950 		case PIC16C5x_TMR0: return R.TMR0;
951 		case PIC16C5x_WDT:  return R.WDT;
952 		case PIC16C5x_PSCL: return R.prescaler;
953 		case PIC16C5x_PRTA: return R.PORTA;
954 		case PIC16C5x_PRTB: return R.PORTB;
955 		case PIC16C5x_PRTC: return R.PORTC;
956 		case PIC16C5x_FSR:  return (R.FSR & picRAMmask);
957 		default:
958 			if (regnum <= REG_SP_CONTENTS)
959 			{
960 				unsigned offset = (REG_SP_CONTENTS - regnum);
961 				if (offset < 2)
962 					return R.STACK[offset];
963 			}
964 			break;
965 	}
966 	return 0;
967 }
968 
969 
970 /****************************************************************************
971  *	Set a specific register
972  ****************************************************************************/
973 
pic16C5x_set_reg(int regnum,unsigned val)974 void pic16C5x_set_reg(int regnum, unsigned val)
975 {
976 	switch (regnum)
977 	{
978 		case REG_PC:
979 		case PIC16C5x_PC: R.PC = val; R.PCL = val & 0xff ; break;
980 		/* This is actually not a stack pointer, but the stack contents */
981 		/* Stack is a 2 level First In Last Out stack */
982 		case REG_SP:
983 		case PIC16C5x_STK1: R.STACK[1] = val; break;
984 		case PIC16C5x_STK0: R.STACK[0] = val; break;
985 		case PIC16C5x_W:    R.W      = val; break;
986 		case PIC16C5x_ALU:  R.ALU    = val; break;
987 		case PIC16C5x_STR:  R.STATUS = val; break;
988 		case PIC16C5x_OPT:  R.OPTION = val; break;
989 		case PIC16C5x_TMR0: R.TMR0   = val; break;
990 		case PIC16C5x_WDT:  R.WDT    = val; break;
991 		case PIC16C5x_PSCL: R.prescaler = val; break;
992 		case PIC16C5x_PRTA: R.PORTA  = val; break;
993 		case PIC16C5x_PRTB: R.PORTB  = val; break;
994 		case PIC16C5x_PRTC: R.PORTC  = val; break;
995 		case PIC16C5x_FSR:  R.FSR    = (val & picRAMmask); break;
996 		default:
997 			if (regnum <= REG_SP_CONTENTS)
998 			{
999 				unsigned offset = (REG_SP_CONTENTS - regnum);
1000 				if (offset < 4)
1001 					R.STACK[offset] = val;
1002 			}
1003 			break;
1004 	}
1005 }
1006 
1007 
1008 /****************************************************************************
1009  *	Set IRQ line state
1010  ****************************************************************************/
1011 
pic16C5x_set_irq_line(int irqline,int state)1012 void pic16C5x_set_irq_line(int irqline, int state)
1013 {
1014 	/* No Interrupt Lines */
1015 }
1016 
pic16C5x_set_irq_callback(int (* callback)(int irqline))1017 void pic16C5x_set_irq_callback(int (*callback)(int irqline))
1018 {
1019 	/* No IRQ Acknowledge Pins on this device */
1020 }
1021 
1022 
1023 /****************************************************************************
1024  *	Debugger definitions
1025  ****************************************************************************/
1026 
1027 #if (HAS_PIC16C55 || HAS_PIC16C57)
1028 static UINT8 pic16C5x_3p_reg_layout[] = {
1029 	PIC16C5x_PC,  PIC16C5x_STK0, PIC16C5x_STK1, PIC16C5x_STR,  PIC16C5x_OPT,  -1,
1030 	PIC16C5x_W,   PIC16C5x_TMR0, PIC16C5x_PSCL, PIC16C5x_PRTA, PIC16C5x_PRTB, PIC16C5x_PRTC, -1,
1031 	PIC16C5x_ALU, PIC16C5x_WDT,  PIC16C5x_FSR,  PIC16C5x_TRSA, PIC16C5x_TRSB, PIC16C5x_TRSC, 0
1032 };
1033 #endif
1034 #if (HAS_PIC16C54 || HAS_PIC16C56 || HAS_PIC16C58)
1035 static UINT8 pic16C5x_2p_reg_layout[] = {
1036 	PIC16C5x_PC,  PIC16C5x_STK0, PIC16C5x_STK1, PIC16C5x_STR,  PIC16C5x_OPT, -1,
1037 	PIC16C5x_W,   PIC16C5x_TMR0, PIC16C5x_PSCL, PIC16C5x_PRTA, PIC16C5x_PRTB, -1,
1038 	PIC16C5x_ALU, PIC16C5x_WDT,  PIC16C5x_FSR,  PIC16C5x_TRSA, PIC16C5x_TRSB, 0
1039 };
1040 #endif
1041 
1042 static UINT8 pic16C5x_win_layout[] = {
1043 	28, 0,53, 3,	/* register window (top rows) */
1044 	 0, 0,27,22,	/* disassembler window (left colums) */
1045 	28, 4,53, 8,	/* memory #1 window (right, upper middle) */
1046 	28,13,53, 9,	/* memory #2 window (right, lower middle) */
1047 	 0,23,80, 1,	/* command line window (bottom rows) */
1048 };
1049 
1050 
1051 
1052 
1053 /****************************************************************************
1054  *	Return a formatted string for a register
1055  ****************************************************************************/
1056 
pic16C5x_info(void * context,int regnum)1057 const char *pic16C5x_info(void *context, int regnum)
1058 {
1059 	static char buffer[18][47+1];
1060 	static int which = 0;
1061 	pic16C5x_Regs *r = context;
1062 
1063 	which = (which+1) % 18;
1064 	buffer[which][0] = '\0';
1065 	if (!context)
1066 		r = &R;
1067 
1068 	switch (regnum)
1069 	{
1070 		case CPU_INFO_REG+PIC16C5x_PC:   sprintf(buffer[which], "PC:%03X",   r->PC); break;
1071 		case CPU_INFO_REG+PIC16C5x_W:    sprintf(buffer[which], "W:%02X",    r->W); break;
1072 		case CPU_INFO_REG+PIC16C5x_ALU:  sprintf(buffer[which], "ALU:%02X",  r->ALU); break;
1073 		case CPU_INFO_REG+PIC16C5x_STR:  sprintf(buffer[which], "STR:%02X",  r->STATUS); break;
1074 		case CPU_INFO_REG+PIC16C5x_TMR0: sprintf(buffer[which], "TMR:%02X",  r->TMR0); break;
1075 		case CPU_INFO_REG+PIC16C5x_WDT:  sprintf(buffer[which], "WDT:%04X",  r->WDT); break;
1076 		case CPU_INFO_REG+PIC16C5x_OPT:  sprintf(buffer[which], "OPT:%02X",  r->OPTION); break;
1077 		case CPU_INFO_REG+PIC16C5x_STK0: sprintf(buffer[which], "STK0:%03X", r->STACK[0]); break;
1078 		case CPU_INFO_REG+PIC16C5x_STK1: sprintf(buffer[which], "STK1:%03X", r->STACK[1]); break;
1079 		case CPU_INFO_REG+PIC16C5x_PRTA: sprintf(buffer[which], "PRTA:%01X", ((r->PORTA) & 0xf)); break;
1080 		case CPU_INFO_REG+PIC16C5x_PRTB: sprintf(buffer[which], "PRTB:%02X", r->PORTB); break;
1081 		case CPU_INFO_REG+PIC16C5x_PRTC: sprintf(buffer[which], "PRTC:%02X", r->PORTC); break;
1082 		case CPU_INFO_REG+PIC16C5x_TRSA: sprintf(buffer[which], "TRSA:%01X", ((r->TRISA) & 0xf)); break;
1083 		case CPU_INFO_REG+PIC16C5x_TRSB: sprintf(buffer[which], "TRSB:%02X", r->TRISB); break;
1084 		case CPU_INFO_REG+PIC16C5x_TRSC: sprintf(buffer[which], "TRSC:%02X", r->TRISC); break;
1085 		case CPU_INFO_REG+PIC16C5x_FSR:  sprintf(buffer[which], "FSR:%02X",  ((r->FSR) & picRAMmask)); break;
1086 		case CPU_INFO_REG+PIC16C5x_PSCL: sprintf(buffer[which], "PSCL:%c%02X", ((r->OPTION & 0x08) ? 'W':'T'), r->prescaler); break;
1087 		case CPU_INFO_FLAGS:
1088 			sprintf(buffer[which], "%01x%c%c%c%c%c %c%c%c%03x",
1089 				(r->STATUS & 0xe0) >> 5,
1090 				r->STATUS & 0x10 ? '.':'O',		/* WDT Overflow */
1091 				r->STATUS & 0x08 ? 'P':'D',		/* Power/Down */
1092 				r->STATUS & 0x04 ? 'Z':'.',		/* Zero */
1093 				r->STATUS & 0x02 ? 'c':'b',		/* Nibble Carry/Borrow */
1094 				r->STATUS & 0x01 ? 'C':'B',		/* Carry/Borrow */
1095 
1096 				r->OPTION & 0x20 ? 'C':'T',		/* Counter/Timer */
1097 				r->OPTION & 0x10 ? 'N':'P',		/* Negative/Positive */
1098 				r->OPTION & 0x08 ? 'W':'T',		/* WatchDog/Timer */
1099 				r->OPTION & 0x08 ? (1<<(r->OPTION&7)) : (2<<(r->OPTION&7)) );
1100 			break;
1101 		case CPU_INFO_NAME: return "PIC16C5x";
1102 		case CPU_INFO_FAMILY: return "Microchip";
1103 		case CPU_INFO_VERSION: return "1.12";
1104 		case CPU_INFO_FILE: return __FILE__;
1105 		case CPU_INFO_CREDITS: return "Copyright (C)2003+ by Tony La Porta";
1106 		case CPU_INFO_REG_LAYOUT: return (const char*)pic16C5x_3p_reg_layout;
1107 		case CPU_INFO_WIN_LAYOUT: return (const char*)pic16C5x_win_layout;
1108 	}
1109 	return buffer[which];
1110 }
1111 
1112 
1113 #if (HAS_PIC16C54)
1114 /****************************************************************************
1115  *	PIC16C54
1116  ****************************************************************************/
1117 
pic16C54_reset(void * param)1118 void pic16C54_reset(void *param)
1119 {
1120 	picmodel = 0x16C54;
1121 	picRAMmask = 0x1f;
1122 	pic16C5x_reset_vector = PIC16C54_RESET_VECTOR;
1123 	pic16C5x_reset_regs();
1124 	R.STATUS = 0x00;
1125 	SET(TO_FLAG);
1126 	SET(PD_FLAG);
1127 }
pic16C54_init(void)1128 void pic16C54_init(void)	{ pic16C5x_init(); }
pic16C54_exit(void)1129 void pic16C54_exit(void)	{ pic16C5x_exit(); }
pic16C54_execute(int cycles)1130 int pic16C54_execute(int cycles) { return pic16C5x_execute(cycles); }
pic16C54_get_context(void * dst)1131 unsigned pic16C54_get_context(void *dst) { return pic16C5x_get_context(dst); }
pic16C54_set_context(void * src)1132 void pic16C54_set_context(void *src) { pic16C5x_set_context(src); }
pic16C54_get_reg(int regnum)1133 unsigned pic16C54_get_reg(int regnum) { return pic16C5x_get_reg(regnum); }
pic16C54_set_reg(int regnum,unsigned val)1134 void pic16C54_set_reg(int regnum, unsigned val) { pic16C5x_set_reg(regnum, val); }
pic16C54_set_irq_line(int irqline,int state)1135 void pic16C54_set_irq_line(int irqline, int state) { pic16C5x_set_irq_line(irqline, state); }
pic16C54_set_irq_callback(int (* callback)(int irqline))1136 void pic16C54_set_irq_callback(int (*callback)(int irqline)) { pic16C5x_set_irq_callback(callback); }
1137 
pic16C54_info(void * context,int regnum)1138 const char *pic16C54_info(void *context, int regnum)
1139 {
1140 	switch( regnum )
1141 	{
1142 		case CPU_INFO_NAME: return "PIC16C54";
1143 		case CPU_INFO_REG_LAYOUT: return (const char*)pic16C5x_2p_reg_layout;
1144 	}
1145 	return pic16C5x_info(context,regnum);
1146 }
1147 
pic16C54_dasm(char * buffer,unsigned pc)1148 unsigned pic16C54_dasm(char *buffer, unsigned pc)
1149 {
1150 #ifdef MAME_DEBUG
1151 	return Dasm16C5x( buffer, pc );
1152 #else
1153 	sprintf( buffer, "$%03X", M_RDOP(pc) );
1154 	return 2;
1155 #endif
1156 }
1157 
1158 #endif
1159 
1160 
1161 #if (HAS_PIC16C55)
1162 /****************************************************************************
1163  *	PIC16C55
1164  ****************************************************************************/
1165 
pic16C55_reset(void * param)1166 void pic16C55_reset(void *param)
1167 {
1168 	picmodel = 0x16C55;
1169 	picRAMmask = 0x1f;
1170 	pic16C5x_reset_vector = PIC16C55_RESET_VECTOR;
1171 	pic16C5x_reset_regs();
1172 	R.STATUS = 0x00;
1173 	SET(TO_FLAG);
1174 	SET(PD_FLAG);
1175 }
pic16C55_init(void)1176 void pic16C55_init(void)	{ pic16C5x_init(); }
pic16C55_exit(void)1177 void pic16C55_exit(void)	{ pic16C5x_exit(); }
pic16C55_execute(int cycles)1178 int pic16C55_execute(int cycles) { return pic16C5x_execute(cycles); }
pic16C55_get_context(void * dst)1179 unsigned pic16C55_get_context(void *dst) { return pic16C5x_get_context(dst); }
pic16C55_set_context(void * src)1180 void pic16C55_set_context(void *src) { pic16C5x_set_context(src); }
pic16C55_get_reg(int regnum)1181 unsigned pic16C55_get_reg(int regnum) { return pic16C5x_get_reg(regnum); }
pic16C55_set_reg(int regnum,unsigned val)1182 void pic16C55_set_reg(int regnum, unsigned val) { pic16C5x_set_reg(regnum, val); }
pic16C55_set_irq_line(int irqline,int state)1183 void pic16C55_set_irq_line(int irqline, int state) { pic16C5x_set_irq_line(irqline, state); }
pic16C55_set_irq_callback(int (* callback)(int irqline))1184 void pic16C55_set_irq_callback(int (*callback)(int irqline)) { pic16C5x_set_irq_callback(callback); }
1185 
pic16C55_info(void * context,int regnum)1186 const char *pic16C55_info(void *context, int regnum)
1187 {
1188 	switch( regnum )
1189 	{
1190 		case CPU_INFO_NAME: return "PIC16C55";
1191 		case CPU_INFO_REG_LAYOUT: return (const char*)pic16C5x_3p_reg_layout;
1192 	}
1193 	return pic16C5x_info(context,regnum);
1194 }
1195 
pic16C55_dasm(char * buffer,unsigned pc)1196 unsigned pic16C55_dasm(char *buffer, unsigned pc)
1197 {
1198 #ifdef MAME_DEBUG
1199 	return Dasm16C5x( buffer, pc );
1200 #else
1201 	sprintf( buffer, "$%03X", M_RDOP(pc) );
1202 	return 2;
1203 #endif
1204 }
1205 
1206 #endif
1207 
1208 
1209 #if (HAS_PIC16C56)
1210 /****************************************************************************
1211  *	PIC16C56
1212  ****************************************************************************/
1213 
pic16C56_reset(void * param)1214 void pic16C56_reset(void *param)
1215 {
1216 	picmodel = 0x16C56;
1217 	picRAMmask = 0x1f;
1218 	pic16C5x_reset_vector = PIC16C56_RESET_VECTOR;
1219 	pic16C5x_reset_regs();
1220 	R.STATUS = 0x00;
1221 	SET(TO_FLAG);
1222 	SET(PD_FLAG);
1223 }
pic16C56_init(void)1224 void pic16C56_init(void)	{ pic16C5x_init(); }
pic16C56_exit(void)1225 void pic16C56_exit(void)	{ pic16C5x_exit(); }
pic16C56_execute(int cycles)1226 int pic16C56_execute(int cycles) { return pic16C5x_execute(cycles); }
pic16C56_get_context(void * dst)1227 unsigned pic16C56_get_context(void *dst) { return pic16C5x_get_context(dst); }
pic16C56_set_context(void * src)1228 void pic16C56_set_context(void *src) { pic16C5x_set_context(src); }
pic16C56_get_reg(int regnum)1229 unsigned pic16C56_get_reg(int regnum) { return pic16C5x_get_reg(regnum); }
pic16C56_set_reg(int regnum,unsigned val)1230 void pic16C56_set_reg(int regnum, unsigned val) { pic16C5x_set_reg(regnum, val); }
pic16C56_set_irq_line(int irqline,int state)1231 void pic16C56_set_irq_line(int irqline, int state) { pic16C5x_set_irq_line(irqline, state); }
pic16C56_set_irq_callback(int (* callback)(int irqline))1232 void pic16C56_set_irq_callback(int (*callback)(int irqline)) { pic16C5x_set_irq_callback(callback); }
1233 
pic16C56_info(void * context,int regnum)1234 const char *pic16C56_info(void *context, int regnum)
1235 {
1236 	switch( regnum )
1237 	{
1238 		case CPU_INFO_NAME: return "PIC16C56";
1239 		case CPU_INFO_REG_LAYOUT: return (const char*)pic16C5x_2p_reg_layout;
1240 	}
1241 	return pic16C5x_info(context,regnum);
1242 }
1243 
pic16C56_dasm(char * buffer,unsigned pc)1244 unsigned pic16C56_dasm(char *buffer, unsigned pc)
1245 {
1246 #ifdef MAME_DEBUG
1247 	return Dasm16C5x( buffer, pc );
1248 #else
1249 	sprintf( buffer, "$%03X", M_RDOP(pc) );
1250 	return 2;
1251 #endif
1252 }
1253 
1254 #endif
1255 
1256 
1257 #if (HAS_PIC16C57)
1258 /****************************************************************************
1259  *	PIC16C57
1260  ****************************************************************************/
1261 
pic16C57_reset(void * param)1262 void pic16C57_reset(void *param)
1263 {
1264 	picmodel = 0x16C57;
1265 	picRAMmask = 0x7f;
1266 	pic16C5x_reset_vector = PIC16C57_RESET_VECTOR;
1267 	pic16C5x_reset_regs();
1268 	R.STATUS = 0x00;
1269 	SET(TO_FLAG);
1270 	SET(PD_FLAG);
1271 }
pic16C57_init(void)1272 void pic16C57_init(void)	{ pic16C5x_init(); }
pic16C57_exit(void)1273 void pic16C57_exit(void)	{ pic16C5x_exit(); }
pic16C57_execute(int cycles)1274 int pic16C57_execute(int cycles) { return pic16C5x_execute(cycles); }
pic16C57_get_context(void * dst)1275 unsigned pic16C57_get_context(void *dst) { return pic16C5x_get_context(dst); }
pic16C57_set_context(void * src)1276 void pic16C57_set_context(void *src) { pic16C5x_set_context(src); }
pic16C57_get_reg(int regnum)1277 unsigned pic16C57_get_reg(int regnum) { return pic16C5x_get_reg(regnum); }
pic16C57_set_reg(int regnum,unsigned val)1278 void pic16C57_set_reg(int regnum, unsigned val) { pic16C5x_set_reg(regnum, val); }
pic16C57_set_irq_line(int irqline,int state)1279 void pic16C57_set_irq_line(int irqline, int state) { pic16C5x_set_irq_line(irqline, state); }
pic16C57_set_irq_callback(int (* callback)(int irqline))1280 void pic16C57_set_irq_callback(int (*callback)(int irqline)) { pic16C5x_set_irq_callback(callback); }
1281 
pic16C57_info(void * context,int regnum)1282 const char *pic16C57_info(void *context, int regnum)
1283 {
1284 	switch( regnum )
1285 	{
1286 		case CPU_INFO_NAME: return "PIC16C57";
1287 		case CPU_INFO_REG_LAYOUT: return (const char*)pic16C5x_3p_reg_layout;
1288 	}
1289 	return pic16C5x_info(context,regnum);
1290 }
1291 
pic16C57_dasm(char * buffer,unsigned pc)1292 unsigned pic16C57_dasm(char *buffer, unsigned pc)
1293 {
1294 #ifdef MAME_DEBUG
1295 	return Dasm16C5x( buffer, pc );
1296 #else
1297 	sprintf( buffer, "$%03X", M_RDOP(pc) );
1298 	return 2;
1299 #endif
1300 }
1301 
1302 #endif
1303 
1304 
1305 #if (HAS_PIC16C58)
1306 /****************************************************************************
1307  *	PIC16C58
1308  ****************************************************************************/
1309 
pic16C58_reset(void * param)1310 void pic16C58_reset(void *param)
1311 {
1312 	picmodel = 0x16C58;
1313 	picRAMmask = 0x7f;
1314 	pic16C5x_reset_vector = PIC16C57_RESET_VECTOR;
1315 	pic16C5x_reset_regs();
1316 	R.STATUS = 0x00;
1317 	SET(TO_FLAG);
1318 	SET(PD_FLAG);
1319 }
pic16C58_init(void)1320 void pic16C58_init(void)	{ pic16C5x_init(); }
pic16C58_exit(void)1321 void pic16C58_exit(void)	{ pic16C5x_exit(); }
pic16C58_execute(int cycles)1322 int pic16C58_execute(int cycles) { return pic16C5x_execute(cycles); }
pic16C58_get_context(void * dst)1323 unsigned pic16C58_get_context(void *dst) { return pic16C5x_get_context(dst); }
pic16C58_set_context(void * src)1324 void pic16C58_set_context(void *src) { pic16C5x_set_context(src); }
pic16C58_get_reg(int regnum)1325 unsigned pic16C58_get_reg(int regnum) { return pic16C5x_get_reg(regnum); }
pic16C58_set_reg(int regnum,unsigned val)1326 void pic16C58_set_reg(int regnum, unsigned val) { pic16C5x_set_reg(regnum, val); }
pic16C58_set_irq_line(int irqline,int state)1327 void pic16C58_set_irq_line(int irqline, int state) { pic16C5x_set_irq_line(irqline, state); }
pic16C58_set_irq_callback(int (* callback)(int irqline))1328 void pic16C58_set_irq_callback(int (*callback)(int irqline)) { pic16C5x_set_irq_callback(callback); }
1329 
pic16C58_info(void * context,int regnum)1330 const char *pic16C58_info(void *context, int regnum)
1331 {
1332 	switch( regnum )
1333 	{
1334 		case CPU_INFO_NAME: return "PIC16C58";
1335 		case CPU_INFO_REG_LAYOUT: return (const char*)pic16C5x_2p_reg_layout;
1336 	}
1337 	return pic16C5x_info(context,regnum);
1338 }
1339 
pic16C58_dasm(char * buffer,unsigned pc)1340 unsigned pic16C58_dasm(char *buffer, unsigned pc)
1341 {
1342 #ifdef MAME_DEBUG
1343 	return Dasm16C5x( buffer, pc );
1344 #else
1345 	sprintf( buffer, "$%03X", M_RDOP(pc) );
1346 	return 2;
1347 #endif
1348 }
1349 
1350 #endif
1351