1  /**************************************************************************\
2  *                      Microchip PIC16C5x Emulator                         *
3  *                                                                          *
4  *                    Copyright 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  *  TLP (27-Aug-2009) Ver 1.13                                              *
35  *   - Indirect addressing was not taking into account special purpose      *
36  *     memory mapped locations.                                             *
37  *   - 'iorlw' instruction was saving the result to memory instead of       *
38  *     the W register.                                                      *
39  *   - 'tris' instruction no longer modifies Port-C on PIC models that      *
40  *     do not have Port-C implemented.                                      *
41  *  TLP (07-Sep-2009) Ver 1.14                                              *
42  *   - Edge sense control for the T0 count input was incorrectly reversed   *
43  *                                                                          *
44  *                                                                          *
45  *  **** Notes: ****                                                        *
46  *  PIC WatchDog Timer has a seperate internal clock. For the moment, we're *
47  *     basing the count on a 4MHz input clock, since 4MHz is the typical    *
48  *     input frequency (but by no means always).                            *
49  *  A single scaler is available for the Counter/Timer or WatchDog Timer.   *
50  *     When connected to the Counter/Timer, it functions as a Prescaler,    *
51  *     hence prescale overflows, tick the Counter/Timer.                    *
52  *     When connected to the WatchDog Timer, it functions as a Postscaler   *
53  *     hence WatchDog Timer overflows, tick the Postscaler. This scenario   *
54  *     means that the WatchDog timeout occurs when the Postscaler has       *
55  *     reached the scaler rate value, not when the WatchDog reaches zero.   *
56  *  CLRWDT should prevent the WatchDog Timer from timing out and generating *
57  *     a device reset, but how is not known. The manual also mentions that  *
58  *     the WatchDog Timer can only be disabled during ROM programming, and  *
59  *     no other means seem to exist???                                      *
60  *                                                                          *
61  \**************************************************************************/
62 
63 
64 
65 //#include "debugger.h"
66 #include "burnint.h"
67 #include "pic16c5x.h"
68 
69 #define CLK 1	/* 1 cycle equals 4 Q-clock ticks */
70 
71 
72 #ifndef INLINE
73 #define INLINE static inline
74 #endif
75 
76 
77 #define M_RDRAM(A)		(((A) < 8) ? R.internalram[A] : PIC16C5x_RAM_RDMEM(A))
78 #define M_WRTRAM(A,V)		do { if ((A) < 8) R.internalram[A] = (V); else PIC16C5x_RAM_WRMEM(A,V); } while (0)
79 #define M_RDOP(A)		PIC16C5x_RDOP(A)
80 #define M_RDOP_ARG(A)		PIC16C5x_RDOP_ARG(A)
81 #define P_IN(A)			PIC16C5x_In(A)
82 #define P_OUT(A,V)		PIC16C5x_Out(A,V)
83 #define S_T0_IN			PIC16C5x_T0_In
84 #define ADDR_MASK		0x7ff
85 
86 #define offs_t	unsigned int
87 
88 
89 typedef struct
90 {
91 	/******************** CPU Internal Registers *******************/
92 	UINT16	PC;
93 	UINT16	PREVPC;		/* previous program counter */
94 	UINT8	W;
95 	UINT8	OPTION;
96 	UINT16	CONFIG;
97 	UINT8	ALU;
98 	UINT16	WDT;
99 	UINT8	TRISA;
100 	UINT8	TRISB;
101 	UINT8	TRISC;
102 	UINT16	STACK[2];
103 	UINT16	prescaler;	/* Note: this is really an 8-bit register */
104 	PAIR	opcode;
105 	UINT8	internalram[8];
106 	UINT32 total_cycles;
107 	INT32   end_run;
108 } pic16C5x_Regs;
109 
110 static pic16C5x_Regs R;
111 static UINT16 temp_config;
112 static UINT8  old_T0;
113 static INT8   old_data;
114 static UINT8  picRAMmask;
115 static int    inst_cycles;
116 static int    delay_timer;
117 static int    picmodel;
118 static int    pic16C5x_reset_vector;
119 static int    pic16C5x_icount;
120 static INT32  slice_cycles;
121 typedef void (*opcode_fn) (void);
122 
123 static const unsigned cycles_000_other[16]=
124 {
125 /*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
126 };
127 
128 #define TMR0	internalram[1]
129 #define PCL		internalram[2]
130 #define STATUS	internalram[3]
131 #define FSR		internalram[4]
132 #define PORTA	internalram[5]
133 #define PORTB	internalram[6]
134 #define PORTC	internalram[7]
135 #define INDF	M_RDRAM(R.FSR)
136 
137 #define ADDR	(R.opcode.b.l & 0x1f)
138 
139 #define  RISING_EDGE_T0  (( (int)(T0_in-old_T0) > 0) ? 1 : 0)
140 #define FALLING_EDGE_T0  (( (int)(T0_in-old_T0) < 0) ? 1 : 0)
141 
142 
143 /********  The following is the Status Flag register definition.  *********/
144 			/* | 7 | 6 | 5 |  4 |  3 | 2 | 1  | 0 | */
145 			/* |    PA     | TO | PD | Z | DC | C | */
146 #define PA_REG		0xe0	/* PA   Program Page Preselect - bit 8 is unused here */
147 #define TO_FLAG		0x10	/* TO   Time Out flag (WatchDog) */
148 #define PD_FLAG		0x08	/* PD   Power Down flag */
149 #define Z_FLAG		0x04	/* Z    Zero Flag */
150 #define DC_FLAG		0x02	/* DC   Digit Carry/Borrow flag (Nibble) */
151 #define C_FLAG		0x01	/* C    Carry/Borrow Flag (Byte) */
152 
153 #define PA		(R.STATUS & PA_REG)
154 #define TO		(R.STATUS & TO_FLAG)
155 #define PD		(R.STATUS & PD_FLAG)
156 #define ZERO	(R.STATUS & Z_FLAG)
157 #define DC		(R.STATUS & DC_FLAG)
158 #define CARRY	(R.STATUS & C_FLAG)
159 
160 
161 /********  The following is the Option Flag register definition.  *********/
162 			/* | 7 | 6 |   5  |   4  |  3  | 2 | 1 | 0 | */
163 			/* | 0 | 0 | TOCS | TOSE | PSA |    PS     | */
164 #define T0CS_FLAG	0x20	/* TOCS     Timer 0 clock source select */
165 #define T0SE_FLAG	0x10	/* TOSE     Timer 0 clock source edge select */
166 #define PSA_FLAG	0x08	/* PSA      Prescaler Assignment bit */
167 #define PS_REG		0x07	/* PS       Prescaler Rate select */
168 
169 #define T0CS	(R.OPTION & T0CS_FLAG)
170 #define T0SE	(R.OPTION & T0SE_FLAG)
171 #define PSA		(R.OPTION & PSA_FLAG)
172 #define PS		(R.OPTION & PS_REG)
173 
174 
175 /********  The following is the Config Flag register definition.  *********/
176 	/* | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 |   2  | 1 | 0 | */
177 	/* |              CP                     | WDTE |  FOSC | */
178 							/* CP       Code Protect (ROM read protect) */
179 #define WDTE_FLAG	0x04	/* WDTE     WatchDog Timer enable */
180 #define FOSC_FLAG	0x03	/* FOSC     Oscillator source select */
181 
182 #define WDTE	(R.CONFIG & WDTE_FLAG)
183 #define FOSC	(R.CONFIG & FOSC_FLAG)
184 
185 
186 /************************************************************************
187  *  Shortcuts
188  ************************************************************************/
189 
190 /* Easy bit position selectors */
191 #define POS	 ((R.opcode.b.l >> 5) & 7)
192 static const unsigned int bit_clr[8] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f };
193 static const unsigned int bit_set[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
194 
195 
CLR(UINT16 flag)196 INLINE void CLR(UINT16 flag) { R.STATUS &= (UINT8)(~flag); }
SET(UINT16 flag)197 INLINE void SET(UINT16 flag) { R.STATUS |=  flag; }
198 
199 
200 
CALCULATE_Z_FLAG(void)201 INLINE void CALCULATE_Z_FLAG(void)
202 {
203 	if (R.ALU == 0) SET(Z_FLAG);
204 	else CLR(Z_FLAG);
205 }
206 
CALCULATE_ADD_CARRY(void)207 INLINE void CALCULATE_ADD_CARRY(void)
208 {
209 	if ((UINT8)(old_data) > (UINT8)(R.ALU)) {
210 		SET(C_FLAG);
211 	}
212 	else {
213 		CLR(C_FLAG);
214 	}
215 }
216 
CALCULATE_ADD_DIGITCARRY(void)217 INLINE void CALCULATE_ADD_DIGITCARRY(void)
218 {
219 	if (((UINT8)(old_data) & 0x0f) > ((UINT8)(R.ALU) & 0x0f)) {
220 		SET(DC_FLAG);
221 	}
222 	else {
223 		CLR(DC_FLAG);
224 	}
225 }
226 
CALCULATE_SUB_CARRY(void)227 INLINE void CALCULATE_SUB_CARRY(void)
228 {
229 	if ((UINT8)(old_data) < (UINT8)(R.ALU)) {
230 		CLR(C_FLAG);
231 	}
232 	else {
233 		SET(C_FLAG);
234 	}
235 }
236 
CALCULATE_SUB_DIGITCARRY(void)237 INLINE void CALCULATE_SUB_DIGITCARRY(void)
238 {
239 	if (((UINT8)(old_data) & 0x0f) < ((UINT8)(R.ALU) & 0x0f)) {
240 		CLR(DC_FLAG);
241 	}
242 	else {
243 		SET(DC_FLAG);
244 	}
245 }
246 
247 
248 
POP_STACK(void)249 INLINE UINT16 POP_STACK(void)
250 {
251 	UINT16 data = R.STACK[1];
252 	R.STACK[1] = R.STACK[0];
253 	return (data & ADDR_MASK);
254 }
PUSH_STACK(UINT16 data)255 INLINE void PUSH_STACK(UINT16 data)
256 {
257 	R.STACK[0] = R.STACK[1];
258 	R.STACK[1] = (data & ADDR_MASK);
259 }
260 
261 
262 //INLINE
GET_REGFILE(offs_t addr)263 UINT8 GET_REGFILE(offs_t addr)	/* Read from internal memory */
264 {
265 	UINT8 data;
266 
267 	if (addr == 0) { /* Indirect addressing */
268 		addr = (R.FSR & picRAMmask);
269 	}
270 
271 	if ((picmodel == 0x16C57) || (picmodel == 0x16C58))
272 	{
273 		addr |= (R.FSR & 0x60);		/* FSR bits 6-5 are used for banking in direct mode */
274 	}
275 	if ((addr & 0x10) == 0) addr &= 0x0f;
276 
277 	switch(addr)
278 	{
279 		case 00:	/* Not an actual register, so return 0 */
280 					data = 0;
281 					break;
282 		case 04:	data = (R.FSR | (UINT8)(~picRAMmask));
283 					break;
284 		case 05:	data = P_IN(0);
285 					data &= R.TRISA;
286 					data |= ((UINT8)(~R.TRISA) & R.PORTA);
287 					data &= 0xf;		/* 4-bit port (only lower 4 bits used) */
288 					break;
289 		case 06:	data = P_IN(1);
290 					data &= R.TRISB;
291 					data |= ((UINT8)(~R.TRISB) & R.PORTB);
292 					break;
293 		case 07:	if ((picmodel == 0x16C55) || (picmodel == 0x16C57)) {
294 						data = P_IN(2);
295 						data &= R.TRISC;
296 						data |= ((UINT8)(~R.TRISC) & R.PORTC);
297 					}
298 					else {		/* PIC16C54, PIC16C56, PIC16C58 */
299 						data = M_RDRAM(addr);
300 					}
301 					break;
302 		default:	data = M_RDRAM(addr);
303 					break;
304 	}
305 
306 	return data;
307 }
308 
309 //INLINE
STORE_REGFILE(offs_t addr,UINT8 data)310 void STORE_REGFILE(offs_t addr, UINT8 data)	/* Write to internal memory */
311 {
312 	if (addr == 0) { /* Indirect addressing */
313 		addr = (R.FSR & picRAMmask);
314 	}
315 
316 	if ((picmodel == 0x16C57) || (picmodel == 0x16C58))
317 	{
318 		addr |= (R.FSR & 0x60);			/* FSR bits 6-5 are used for banking in direct mode */
319 	}
320 	if ((addr & 0x10) == 0) addr &= 0x0f;
321 
322 	switch(addr)
323 	{
324 		case 00:	/* Not an actual register, nothing to save */
325 					break;
326 		case 01:	delay_timer = 2;		/* Timer starts after next two instructions */
327 					if (PSA == 0) R.prescaler = 0;	/* Must clear the Prescaler */
328 					R.TMR0 = data;
329 					break;
330 		case 02:	R.PCL = data;
331 					R.PC = ((R.STATUS & PA_REG) << 4) | data;
332 					break;
333 		case 03:	R.STATUS &= (UINT8)(~PA_REG); R.STATUS |= (data & PA_REG);
334 					break;
335 		case 04:	R.FSR = (data | (UINT8)(~picRAMmask));
336 					break;
337 		case 05:	data &= 0xf;		/* 4-bit port (only lower 4 bits used) */
338 					P_OUT(0,data & (UINT8)(~R.TRISA)); R.PORTA = data;
339 					break;
340 		case 06:	P_OUT(1,data & (UINT8)(~R.TRISB)); R.PORTB = data;
341 					break;
342 		case 07:	if ((picmodel == 0x16C55) || (picmodel == 0x16C57)) {
343 						P_OUT(2,data & (UINT8)(~R.TRISC));
344 						R.PORTC = data;
345 					}
346 					else {		/* PIC16C54, PIC16C56, PIC16C58 */
347 						M_WRTRAM(addr, data);
348 					}
349 					break;
350 		default:	M_WRTRAM(addr, data);
351 					break;
352 	}
353 }
354 
355 
STORE_RESULT(offs_t addr,UINT8 data)356 INLINE void STORE_RESULT(offs_t addr, UINT8 data)
357 {
358 	if (R.opcode.b.l & 0x20)
359 	{
360 		STORE_REGFILE(addr, data);
361 	}
362 	else
363 	{
364 		R.W = data;
365 	}
366 }
367 
368 
369 /************************************************************************
370  *  Emulate the Instructions
371  ************************************************************************/
372 
373 /* This following function is here to fill in the void for */
374 /* the opcode call function. This function is never called. */
375 
376 
illegal(void)377 static void illegal(void)
378 {
379 
380 }
381 
382 
addwf(void)383 static void addwf(void)
384 {
385 	old_data = GET_REGFILE(ADDR);
386 	R.ALU = old_data + R.W;
387 	STORE_RESULT(ADDR, R.ALU);
388 	CALCULATE_Z_FLAG();
389 	CALCULATE_ADD_CARRY();
390 	CALCULATE_ADD_DIGITCARRY();
391 }
392 
andwf(void)393 static void andwf(void)
394 {
395 	R.ALU = GET_REGFILE(ADDR) & R.W;
396 	STORE_RESULT(ADDR, R.ALU);
397 	CALCULATE_Z_FLAG();
398 }
399 
andlw(void)400 static void andlw(void)
401 {
402 	R.ALU = R.opcode.b.l & R.W;
403 	R.W = R.ALU;
404 	CALCULATE_Z_FLAG();
405 }
406 
bcf(void)407 static void bcf(void)
408 {
409 	R.ALU = GET_REGFILE(ADDR);
410 	R.ALU &= bit_clr[POS];
411 	STORE_REGFILE(ADDR, R.ALU);
412 }
413 
bsf(void)414 static void bsf(void)
415 {
416 	R.ALU = GET_REGFILE(ADDR);
417 	R.ALU |= bit_set[POS];
418 	STORE_REGFILE(ADDR, R.ALU);
419 }
420 
btfss(void)421 static void btfss(void)
422 {
423 	if ((GET_REGFILE(ADDR) & bit_set[POS]) == bit_set[POS])
424 	{
425 		R.PC++ ;
426 		R.PCL = R.PC & 0xff;
427 		inst_cycles += 1;		/* Add NOP cycles */
428 	}
429 }
430 
btfsc(void)431 static void btfsc(void)
432 {
433 	if ((GET_REGFILE(ADDR) & bit_set[POS]) == 0)
434 	{
435 		R.PC++ ;
436 		R.PCL = R.PC & 0xff;
437 		inst_cycles += 1;		/* Add NOP cycles */
438 	}
439 }
440 
call(void)441 static void call(void)
442 {
443 	PUSH_STACK(R.PC);
444 	R.PC = ((R.STATUS & PA_REG) << 4) | R.opcode.b.l;
445 	R.PC &= 0x6ff;
446 	R.PCL = R.PC & 0xff;
447 }
448 
clrw(void)449 static void clrw(void)
450 {
451 	R.W = 0;
452 	SET(Z_FLAG);
453 }
454 
clrf(void)455 static void clrf(void)
456 {
457 	STORE_REGFILE(ADDR, 0);
458 	SET(Z_FLAG);
459 }
460 
clrwdt(void)461 static void clrwdt(void)
462 {
463 	R.WDT = 0;
464 	if (PSA) R.prescaler = 0;
465 	SET(TO_FLAG);
466 	SET(PD_FLAG);
467 }
468 
comf(void)469 static void comf(void)
470 {
471 	R.ALU = (UINT8)(~(GET_REGFILE(ADDR)));
472 	STORE_RESULT(ADDR, R.ALU);
473 	CALCULATE_Z_FLAG();
474 }
475 
decf(void)476 static void decf(void)
477 {
478 	R.ALU = GET_REGFILE(ADDR) - 1;
479 	STORE_RESULT(ADDR, R.ALU);
480 	CALCULATE_Z_FLAG();
481 }
482 
decfsz(void)483 static void decfsz(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 += 1;		/* Add NOP cycles */
492 	}
493 }
494 
goto_op(void)495 static void goto_op(void)
496 {
497 	R.PC = ((R.STATUS & PA_REG) << 4) | (R.opcode.w.l & 0x1ff);
498 	R.PC &= ADDR_MASK;
499 	R.PCL = R.PC & 0xff;
500 }
501 
incf(void)502 static void incf(void)
503 {
504 	R.ALU = GET_REGFILE(ADDR) + 1;
505 	STORE_RESULT(ADDR, R.ALU);
506 	CALCULATE_Z_FLAG();
507 }
508 
incfsz(void)509 static void incfsz(void)
510 {
511 	R.ALU = GET_REGFILE(ADDR) + 1;
512 	STORE_RESULT(ADDR, R.ALU);
513 	if (R.ALU == 0)
514 	{
515 		R.PC++ ;
516 		R.PCL = R.PC & 0xff;
517 		inst_cycles += 1;		/* Add NOP cycles */
518 	}
519 }
520 
iorlw(void)521 static void iorlw(void)
522 {
523 	R.ALU = R.opcode.b.l | R.W;
524 	R.W = R.ALU;
525 	CALCULATE_Z_FLAG();
526 }
527 
iorwf(void)528 static void iorwf(void)
529 {
530 	R.ALU = GET_REGFILE(ADDR) | R.W;
531 	STORE_RESULT(ADDR, R.ALU);
532 	CALCULATE_Z_FLAG();
533 }
534 
movf(void)535 static void movf(void)
536 {
537 	R.ALU = GET_REGFILE(ADDR);
538 	STORE_RESULT(ADDR, R.ALU);
539 	CALCULATE_Z_FLAG();
540 }
541 
movlw(void)542 static void movlw(void)
543 {
544 	R.W = R.opcode.b.l;
545 }
546 
movwf(void)547 static void movwf(void)
548 {
549 	STORE_REGFILE(ADDR, R.W);
550 }
551 
nop(void)552 static void nop(void)
553 {
554 	/* Do nothing */
555 }
556 
option(void)557 static void option(void)
558 {
559 	R.OPTION = R.W & (T0CS_FLAG | T0SE_FLAG | PSA_FLAG | PS_REG);
560 }
561 
retlw(void)562 static void retlw(void)
563 {
564 	R.W = R.opcode.b.l;
565 	R.PC = POP_STACK();
566 	R.PCL = R.PC & 0xff;
567 }
568 
rlf(void)569 static void rlf(void)
570 {
571 	R.ALU = GET_REGFILE(ADDR);
572 	R.ALU <<= 1;
573 	if (R.STATUS & C_FLAG) R.ALU |= 1;
574 	if (GET_REGFILE(ADDR) & 0x80) SET(C_FLAG);
575 	else CLR(C_FLAG);
576 	STORE_RESULT(ADDR, R.ALU);
577 }
578 
rrf(void)579 static void rrf(void)
580 {
581 	R.ALU = GET_REGFILE(ADDR);
582 	R.ALU >>= 1;
583 	if (R.STATUS & C_FLAG) R.ALU |= 0x80;
584 	if (GET_REGFILE(ADDR) & 1) SET(C_FLAG);
585 	else CLR(C_FLAG);
586 	STORE_RESULT(ADDR, R.ALU);
587 }
588 
sleepic(void)589 static void sleepic(void)
590 {
591 	if (WDTE) R.WDT = 0;
592 	if (PSA) R.prescaler = 0;
593 	SET(TO_FLAG);
594 	CLR(PD_FLAG);
595 }
596 
subwf(void)597 static void subwf(void)
598 {
599 	old_data = GET_REGFILE(ADDR);
600 	R.ALU = old_data - R.W;
601 	STORE_RESULT(ADDR, R.ALU);
602 	CALCULATE_Z_FLAG();
603 	CALCULATE_SUB_CARRY();
604 	CALCULATE_SUB_DIGITCARRY();
605 }
606 
swapf(void)607 static void swapf(void)
608 {
609 	R.ALU  = ((GET_REGFILE(ADDR) << 4) & 0xf0);
610 	R.ALU |= ((GET_REGFILE(ADDR) >> 4) & 0x0f);
611 	STORE_RESULT(ADDR, R.ALU);
612 }
613 
tris(void)614 static void tris(void)
615 {
616 	switch(R.opcode.b.l & 0x7)
617 	{
618 		case 05:	if (R.TRISA == R.W) break;
619 					else R.TRISA = R.W | 0xf0; P_OUT(0,R.PORTA & (UINT8)(~R.TRISA) & 0xf); break;
620 		case 06:	if (R.TRISB == R.W) break;
621 					else R.TRISB = R.W; P_OUT(1,R.PORTB & (UINT8)(~R.TRISB)); break;
622 		case 07:	if ((picmodel == 0x16C55) || (picmodel == 0x16C57)) {
623 						if (R.TRISC == R.W) break;
624 						else R.TRISC = R.W; P_OUT(2,R.PORTC & (UINT8)(~R.TRISC)); break;
625 					} else {
626 						illegal(); break;
627 					}
628 		default:	illegal(); break;
629 	}
630 }
631 
xorlw(void)632 static void xorlw(void)
633 {
634 	R.ALU = R.W ^ R.opcode.b.l;
635 	R.W = R.ALU;
636 	CALCULATE_Z_FLAG();
637 }
638 
xorwf(void)639 static void xorwf(void)
640 {
641 	R.ALU = GET_REGFILE(ADDR) ^ R.W;
642 	STORE_RESULT(ADDR, R.ALU);
643 	CALCULATE_Z_FLAG();
644 }
645 
646 
647 
648 /***********************************************************************
649  *  Cycle Timings
650  ***********************************************************************/
651 
652 static const unsigned cycles_main[256]=
653 {
654 /*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,
655 /*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,
656 /*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,
657 
658 
659 /*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,
660 /*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,
661 /*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,
662 /*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,
663 /*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,
664 /*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,
665 /*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,
666 /*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,
667 /*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,
668 /*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,
669 /*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,
670 /*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,
671 /*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
672 };
673 
674 static const opcode_fn opcode_main[256]=
675 {
676 /*00*/  nop,	illegal,movwf,	movwf,	clrw,	illegal,clrf,	clrf,
677 /*08*/  subwf,	subwf,	subwf,	subwf,	decf,	decf,	decf,	decf,
678 /*10*/  iorwf,	iorwf,	iorwf,	iorwf,	andwf,	andwf,	andwf,	andwf,
679 /*18*/  xorwf,	xorwf,	xorwf,	xorwf,	addwf,	addwf,	addwf,	addwf,
680 /*20*/  movf,	movf,	movf,	movf,	comf,	comf,	comf,	comf,
681 /*28*/  incf,	incf,	incf,	incf,	decfsz,	decfsz,	decfsz,	decfsz,
682 /*30*/  rrf,	rrf,	rrf,	rrf,	rlf,	rlf,	rlf,	rlf,
683 /*38*/  swapf,	swapf,	swapf,	swapf,	incfsz,	incfsz,	incfsz,	incfsz,
684 /*40*/  bcf,	bcf,	bcf,	bcf,	bcf,	bcf,	bcf,	bcf,
685 /*48*/  bcf,	bcf,	bcf,	bcf,	bcf,	bcf,	bcf,	bcf,
686 /*50*/  bsf,	bsf,	bsf,	bsf,	bsf,	bsf,	bsf,	bsf,
687 /*58*/  bsf,	bsf,	bsf,	bsf,	bsf,	bsf,	bsf,	bsf,
688 /*60*/  btfsc,	btfsc,	btfsc,	btfsc,	btfsc,	btfsc,	btfsc,	btfsc,
689 /*68*/  btfsc,	btfsc,	btfsc,	btfsc,	btfsc,	btfsc,	btfsc,	btfsc,
690 /*70*/  btfss,	btfss,	btfss,	btfss,	btfss,	btfss,	btfss,	btfss,
691 /*78*/  btfss,	btfss,	btfss,	btfss,	btfss,	btfss,	btfss,	btfss,
692 /*80*/  retlw,	retlw,	retlw,	retlw,	retlw,	retlw,	retlw,	retlw,
693 /*88*/  retlw,	retlw,	retlw,	retlw,	retlw,	retlw,	retlw,	retlw,
694 /*90*/  call,	call,	call,	call,	call,	call,	call,	call,
695 /*98*/  call,	call,	call,	call,	call,	call,	call,	call,
696 /*A0*/  goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,
697 /*A8*/  goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,
698 /*B0*/  goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,
699 /*B8*/  goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,goto_op,
700 /*C0*/  movlw,	movlw,	movlw,	movlw,	movlw,	movlw,	movlw,	movlw,
701 /*C8*/  movlw,	movlw,	movlw,	movlw,	movlw,	movlw,	movlw,	movlw,
702 /*D0*/  iorlw,	iorlw,	iorlw,	iorlw,	iorlw,	iorlw,	iorlw,	iorlw,
703 /*D8*/  iorlw,	iorlw,	iorlw,	iorlw,	iorlw,	iorlw,	iorlw,	iorlw,
704 /*E0*/  andlw,	andlw,	andlw,	andlw,	andlw,	andlw,	andlw,	andlw,
705 /*E8*/  andlw,	andlw,	andlw,	andlw,	andlw,	andlw,	andlw,	andlw,
706 /*F0*/  xorlw,	xorlw,	xorlw,	xorlw,	xorlw,	xorlw,	xorlw,	xorlw,
707 /*F8*/  xorlw,	xorlw,	xorlw,	xorlw,	xorlw,	xorlw,	xorlw,	xorlw
708 };
709 
710 
711 //static const unsigned cycles_000_other[16]=
712 //{
713 ///*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
714 //};
715 
716 static const opcode_fn opcode_000_other[16]=
717 {
718 /*00*/  nop,	illegal,option,	sleepic,clrwdt,	tris,	tris,	tris,
719 /*08*/  illegal,illegal,illegal,illegal,illegal,illegal,illegal,illegal
720 };
721 
722 /****************************************************************************
723  *  Reset registers to their initial values
724  ****************************************************************************/
725 
pic16C5x_reset_regs(void)726 static void pic16C5x_reset_regs(void)
727 {
728 	R.PC     = pic16C5x_reset_vector;
729 	R.CONFIG = temp_config;
730 	R.TRISA  = 0xff;
731 	R.TRISB  = 0xff;
732 	R.TRISC  = 0xff;
733 	R.OPTION = (T0CS_FLAG | T0SE_FLAG | PSA_FLAG | PS_REG);
734 	R.PCL    = 0xff;
735 	R.FSR   |= (UINT8)(~picRAMmask);
736 	R.PORTA &= 0x0f;
737 	R.prescaler = 0;
738 	delay_timer = 0;
739 	old_T0      = 0;
740 	inst_cycles = 0;
741 }
742 
pic16C5x_soft_reset(void)743 static void pic16C5x_soft_reset(void)
744 {
745 //	R.STATUS &= 0x1f;
746 	SET((TO_FLAG | PD_FLAG | Z_FLAG | DC_FLAG | C_FLAG));
747 	pic16C5x_reset_regs();
748 }
749 
pic16c5x_config(int data)750 void pic16c5x_config(int data)
751 {
752 //	logerror("Writing %04x to the PIC16C5x config register\n",data);
753 	temp_config = (data & 0xfff);
754 }
755 
756 
757 /****************************************************************************
758  *  Shut down CPU emulation
759  ****************************************************************************/
760 
pic16C5x_exit(void)761 void pic16C5x_exit (void)
762 {
763 	/* nothing to do */
764 }
765 
766 
767 /****************************************************************************
768  *  WatchDog
769  ****************************************************************************/
770 
pic16C5x_update_watchdog(int counts)771 static void pic16C5x_update_watchdog(int counts)
772 {
773 	/* WatchDog is set up to count 18,000 (0x464f hex) ticks to provide */
774 	/* the timeout period of 0.018ms based on a 4MHz input clock. */
775 	/* Note: the 4MHz clock should be divided by the PIC16C5x_CLOCK_DIVIDER */
776 	/* which effectively makes the PIC run at 1MHz internally. */
777 
778 	/* If the current instruction is CLRWDT or SLEEP, don't update the WDT */
779 
780 	if ((R.opcode.w.l != 3) && (R.opcode.w.l != 4))
781 	{
782 		UINT16 old_WDT = R.WDT;
783 
784 		R.WDT -= counts;
785 
786 		if (R.WDT > 0x464f) {
787 			R.WDT = 0x464f - (0xffff - R.WDT);
788 		}
789 
790 		if (((old_WDT != 0) && (old_WDT < R.WDT)) || (R.WDT == 0))
791 		{
792 			if (PSA) {
793 				R.prescaler++;
794 				if (R.prescaler >= (1 << PS)) {	/* Prescale values from 1 to 128 */
795 					R.prescaler = 0;
796 					CLR(TO_FLAG);
797 					pic16C5x_soft_reset();
798 				}
799 			}
800 			else {
801 				CLR(TO_FLAG);
802 				pic16C5x_soft_reset();
803 			}
804 		}
805 	}
806 }
807 
808 
809 /****************************************************************************
810  *  Update Timer
811  ****************************************************************************/
812 
pic16C5x_update_timer(int counts)813 static void pic16C5x_update_timer(int counts)
814 {
815 	if (PSA == 0) {
816 		R.prescaler += counts;
817 		if (R.prescaler >= (2 << PS)) {	/* Prescale values from 2 to 256 */
818 			R.TMR0 += (R.prescaler / (2 << PS));
819 			R.prescaler %= (2 << PS);	/* Overflow prescaler */
820 		}
821 	}
822 	else {
823 		R.TMR0 += counts;
824 	}
825 }
826 
827 
828 /****************************************************************************
829  *  Execute IPeriod. Return 0 if emulation should be stopped
830  ****************************************************************************/
831 
pic16c5xRun(int cycles)832 int pic16c5xRun(int cycles)
833 {
834 	UINT8 T0_in;
835 	slice_cycles = cycles;
836 	pic16C5x_icount = cycles;
837 	R.end_run = 0;
838 
839 	do
840 	{
841 		if (PD == 0)						/* Sleep Mode */
842 		{
843 			inst_cycles = (1*CLK);
844 
845 			if (WDTE) {
846 				pic16C5x_update_watchdog(1*CLK);
847 			}
848 		}
849 		else
850 		{
851 			R.PREVPC = R.PC;
852 			R.opcode.d = M_RDOP(R.PC);
853 
854 			R.PC++;
855 			R.PCL++;
856 
857 			if ((R.opcode.w.l & 0xff0) != 0x000)	{	/* Do all opcodes except the 00? ones */
858 				inst_cycles = cycles_main[((R.opcode.w.l >> 4) & 0xff)];
859 				(*(opcode_main[((R.opcode.w.l >> 4) & 0xff)]))();
860 			}
861 			else {	/* Opcode 0x00? has many opcodes in its minor nibble */
862 				inst_cycles = cycles_000_other[(R.opcode.b.l & 0x1f)];
863 				(*(opcode_000_other[(R.opcode.b.l & 0x1f)]))();
864 			}
865 
866 			if (T0CS) {						/* Count mode */
867 				T0_in = S_T0_IN;
868 				if (T0_in) T0_in = 1;
869 				if (T0SE) {					/* Count falling edge T0 input */
870 					if (FALLING_EDGE_T0) {
871 						pic16C5x_update_timer(1);
872 					}
873 				}
874 				else {						/* Count rising edge T0 input */
875 					if (RISING_EDGE_T0) {
876 						pic16C5x_update_timer(1);
877 					}
878 				}
879 				old_T0 = T0_in;
880 			}
881 			else {							/* Timer mode */
882 				if (delay_timer) {
883 					delay_timer--;
884 				}
885 				else {
886 					pic16C5x_update_timer((inst_cycles/CLK));
887 				}
888 			}
889 			if (WDTE) {
890 				pic16C5x_update_watchdog((inst_cycles/CLK));
891 			}
892 		}
893 
894 		pic16C5x_icount -= inst_cycles;
895 
896 	} while (pic16C5x_icount>0 && !R.end_run);
897 
898 	cycles = cycles - pic16C5x_icount;
899 
900 	R.total_cycles += cycles;
901 	slice_cycles = 0;
902 	pic16C5x_icount = 0;
903 
904 	return cycles;
905 }
906 
907 
pic16C54_reset(void)908 static void pic16C54_reset(void)
909 {
910 	picmodel = 0x16C54;
911 	picRAMmask = 0x1f;
912 	pic16C5x_reset_vector = 0x1ff;
913 	pic16C5x_reset_regs();
914 	CLR(PA_REG);
915 	SET((TO_FLAG | PD_FLAG));
916 }
917 
pic16C55_reset(void)918 static void pic16C55_reset(void)
919 {
920 	picmodel = 0x16C55;
921 	picRAMmask = 0x1f;
922 	pic16C5x_reset_vector = 0x1ff;
923 	pic16C5x_reset_regs();
924 	CLR(PA_REG);
925 	SET((TO_FLAG | PD_FLAG));
926 }
927 
pic16C56_reset(void)928 static void pic16C56_reset(void)
929 {
930 	picmodel = 0x16C56;
931 	picRAMmask = 0x1f;
932 	pic16C5x_reset_vector = 0x3ff;
933 	pic16C5x_reset_regs();
934 	CLR(PA_REG);
935 	SET((TO_FLAG | PD_FLAG));
936 }
937 
pic16C57_reset(void)938 static void pic16C57_reset(void)
939 {
940 	picmodel = 0x16C57;
941 	picRAMmask = 0x7f;
942 	pic16C5x_reset_vector = 0x7ff;
943 	pic16C5x_reset_regs();
944 	CLR(PA_REG);
945 	SET((TO_FLAG | PD_FLAG));
946 }
947 
pic16C58_reset(void)948 static void pic16C58_reset(void)
949 {
950 	picmodel = 0x16C58;
951 	picRAMmask = 0x7f;
952 	pic16C5x_reset_vector = 0x7ff;
953 	pic16C5x_reset_regs();
954 	CLR(PA_REG);
955 	SET((TO_FLAG | PD_FLAG));
956 }
957 
958 
pic16c5xDoReset(int type,int * romlen,int * ramlen)959 void pic16c5xDoReset(int type, int *romlen, int *ramlen)
960 {
961 	switch (type)
962 	{
963 		case 0x16C54:
964 			pic16C54_reset();
965 			*romlen = 0x1ff;
966 			*ramlen = 0x01f;
967 		return;
968 
969 		case 0x16C55:
970 			pic16C55_reset();
971 			*romlen = 0x3ff; // correct?
972 			*ramlen = 0x01f;
973 		return;
974 
975 		case 0x16C56:
976 			pic16C56_reset();
977 			*romlen = 0x3ff;
978 			*ramlen = 0x01f;
979 		return;
980 
981 		case 0x16C57:
982 			pic16C57_reset();
983 			*romlen = 0x7ff;
984 			*ramlen = 0x07f;
985 		return;
986 
987 		case 0x16C58:
988 			pic16C58_reset();
989 			*romlen = 0x7ff;
990 			*ramlen = 0x07f;
991 		return;
992 	}
993 }
994 
pic16c5xTotalCycles()995 INT32 pic16c5xTotalCycles()
996 {
997 	return R.total_cycles + (slice_cycles - pic16C5x_icount);
998 }
999 
pic16c5xNewFrame()1000 void pic16c5xNewFrame()
1001 {
1002 	R.total_cycles = 0;
1003 }
1004 
pic16c5xRunEnd()1005 void pic16c5xRunEnd()
1006 {
1007 	R.end_run = 1;
1008 }
1009 
pic16c5xIdle(INT32 cycles)1010 INT32 pic16c5xIdle(INT32 cycles)
1011 {
1012 	R.total_cycles += cycles;
1013 
1014 	return cycles;
1015 }
1016 
pic16c5xScanCpu(int nAction,int *)1017 int pic16c5xScanCpu(int nAction,int */*pnMin*/)
1018 {
1019 	struct BurnArea ba;
1020 
1021 	if (nAction & ACB_DRIVER_DATA) {
1022 		SCAN_VAR(R.PC);
1023 		SCAN_VAR(R.PREVPC);
1024 		SCAN_VAR(R.W);
1025 		SCAN_VAR(R.OPTION);
1026 		SCAN_VAR(R.CONFIG);
1027 		SCAN_VAR(R.ALU);
1028 		SCAN_VAR(R.WDT);
1029 		SCAN_VAR(R.TRISA);
1030 		SCAN_VAR(R.TRISC);
1031 		SCAN_VAR(R.STACK[0]);
1032 		SCAN_VAR(R.STACK[1]);
1033 		SCAN_VAR(R.prescaler);
1034 		SCAN_VAR(R.opcode);
1035 		SCAN_VAR(R.total_cycles);
1036 	}
1037 
1038 	if (nAction & ACB_MEMORY_RAM) {
1039 		ba.Data		= R.internalram;
1040 		ba.nLen		= 8;
1041 		ba.nAddress = 0;
1042 		ba.szName	= "Internal RAM";
1043 		BurnAcb(&ba);
1044 	}
1045 
1046 	return 0;
1047 }
1048