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