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