summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--.gitattributes4
-rw-r--r--src/emu/cpu/cpu.mak15
-rw-r--r--src/emu/cpu/pic16c62x/16c62xdsm.c269
-rw-r--r--src/emu/cpu/pic16c62x/dis16c62x.c136
-rw-r--r--src/emu/cpu/pic16c62x/pic16c62x.c1607
-rw-r--r--src/emu/cpu/pic16c62x/pic16c62x.h84
-rw-r--r--src/mame/mame.mak1
-rw-r--r--src/tools/unidasm.c2
8 files changed, 2118 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes
index 18439c0621e..6c5a5a8ae46 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -313,6 +313,10 @@ src/emu/cpu/pic16c5x/16c5xdsm.c svneol=native#text/plain
src/emu/cpu/pic16c5x/dis16c5x.c svneol=native#text/plain
src/emu/cpu/pic16c5x/pic16c5x.c svneol=native#text/plain
src/emu/cpu/pic16c5x/pic16c5x.h svneol=native#text/plain
+src/emu/cpu/pic16c62x/16c62xdsm.c svneol=native#text/plain
+src/emu/cpu/pic16c62x/dis16c62x.c svneol=native#text/plain
+src/emu/cpu/pic16c62x/pic16c62x.c svneol=native#text/plain
+src/emu/cpu/pic16c62x/pic16c62x.h svneol=native#text/plain
src/emu/cpu/powerpc/drc_ops.c svneol=native#text/plain
src/emu/cpu/powerpc/drc_ops.h svneol=native#text/plain
src/emu/cpu/powerpc/ppc.c svneol=native#text/plain
diff --git a/src/emu/cpu/cpu.mak b/src/emu/cpu/cpu.mak
index c96fc976eb4..b9da625b67c 100644
--- a/src/emu/cpu/cpu.mak
+++ b/src/emu/cpu/cpu.mak
@@ -789,6 +789,21 @@ $(CPUOBJ)/pic16c5x/pic16c5x.o: $(CPUSRC)/pic16c5x/pic16c5x.c \
#-------------------------------------------------
+# Microchip PIC16C62x
+#-------------------------------------------------
+
+ifneq ($(filter PIC16C62X,$(CPUS)),)
+OBJDIRS += $(CPUOBJ)/pic16c62x
+CPUOBJS += $(CPUOBJ)/pic16c62x/pic16c62x.o
+DASMOBJS += $(CPUOBJ)/pic16c62x/16c62xdsm.o
+endif
+
+$(CPUOBJ)/pic16c62x/pic16c62x.o: $(CPUSRC)/pic16c62x/pic16c62x.c \
+ $(CPUSRC)/pic16c62x/pic16c62x.h
+
+
+
+#-------------------------------------------------
# MIPS R3000 (MIPS I/II) series
# MIPS R4000 (MIPS III/IV) series
# Sony PlayStation CPU (R3000-based + GTE)
diff --git a/src/emu/cpu/pic16c62x/16c62xdsm.c b/src/emu/cpu/pic16c62x/16c62xdsm.c
new file mode 100644
index 00000000000..6f18d73e60f
--- /dev/null
+++ b/src/emu/cpu/pic16c62x/16c62xdsm.c
@@ -0,0 +1,269 @@
+ /**************************************************************************\
+ * Microchip PIC16C62X Emulator *
+ * *
+ * Based On *
+ * Microchip PIC16C5X Emulator *
+ * Copyright Tony La Porta *
+ * Originally written for the MAME project. *
+ * *
+ * *
+ * Addressing architecture is based on the Harvard addressing scheme. *
+ * *
+ * Many thanks to those involved in the i8039 Disassembler *
+ * as this was based on it. *
+ * *
+ * *
+ * *
+ * A Address to jump to. *
+ * B Bit address within an 8-bit file register. *
+ * D Destination select (0 = store result in W (accumulator)) *
+ * (1 = store result in file register) *
+ * F Register file address (00-1F). *
+ * K Literal field, constant data. *
+ * X Not used *
+ * *
+ \**************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "cpuintrf.h"
+#include "mame.h"
+static const UINT8 *rombase;
+static const UINT8 *rambase;
+static offs_t pcbase;
+#define READOP16(A) (rombase[(A) - pcbase] | (rombase[(A) + 1 - pcbase] << 8))
+#define READARG16(A) (rambase[(A) - pcbase] | (rambase[(A) + 1 - pcbase] << 8))
+
+
+
+typedef unsigned char byte;
+typedef unsigned short int word;
+
+#define FMT(a,b) a, b
+#define PTRS_PER_FORMAT 2
+
+/* Registers bank 0/1 */
+static const char *const regfile[32] = { "Reg$00 (INDF)", "Reg$01 (TMR0/OPTION)", "Reg$02 (PCL)", "Reg$03 (STATUS)", "Reg$04 (FSR)", "Reg$05 (PORTA/TRISA)", "Reg$06 (PORTB/TRISB)", "Reg$07",
+ "Reg$08", "Reg$09", "Reg$0A (PCLATH)", "Reg$0B (INTCON)", "Reg$0C (PIR1/PIE1)", "Reg$0D", "Reg$0E (none/PCON)", "Reg$0F",
+ "Reg$10", "Reg$11", "Reg$12", "Reg$13", "Reg$14", "Reg$15", "Reg$16", "Reg$17",
+ "Reg$18", "Reg$19", "Reg$1A", "Reg$1B", "Reg$1C", "Reg$1D", "Reg$1E", "Reg$1F (CMCON/VRCON)" };
+/* Registers bank 1 */
+/*static const char *const regfile1[32] = { "Reg$00 (INDF)", "Reg$01 (OPTION)", "Reg$02 (PCL)", "Reg$03 (STATUS)", "Reg$04 (FSR)", "Reg$05 (TRISA)", "Reg$06 (TRISB)", "Reg$07",
+ "Reg$08", "Reg$09", "Reg$0A (PCLATH)", "Reg$0B (INTCON)", "Reg$0C (PIE1)", "Reg$0D", "Reg$0E (PCON)", "Reg$0F",
+ "Reg$10", "Reg$11", "Reg$12", "Reg$13", "Reg$14", "Reg$15", "Reg$16", "Reg$17",
+ "Reg$18", "Reg$19", "Reg$1A", "Reg$1B", "Reg$1C", "Reg$1D", "Reg$1E", "Reg$1F (VRCON)" };
+static const char **regfile[2] = { regfile0, regfile1 };*/
+
+static const char *const dest[2] = { "W", "Reg" };
+
+static const char *const PIC16C62xFormats[] = {
+ FMT("0000000xx00000", "nop"),
+ FMT("00000000001000", "return"),
+ FMT("00000000001001", "retfie"),
+ FMT("00000001100011", "sleep"),
+ FMT("00000001100100", "clrwdt"),
+ FMT("0000001fffffff", "movwf %F"),
+ FMT("00000100000011", "clrw"),
+ FMT("0000011fffffff", "clrf %F"),
+ FMT("000010dfffffff", "subwf %F,%D"),
+ FMT("000011dfffffff", "decf %F,%D"),
+ FMT("000100dfffffff", "iorwf %F,%D"),
+ FMT("000101dfffffff", "andwf %F,%D"),
+ FMT("000110dfffffff", "xorwf %F,%D"),
+ FMT("000111dfffffff", "addwf %F,%D"),
+ FMT("001000dfffffff", "movf %F,%D"),
+ FMT("001001dfffffff", "comf %F,%D"),
+ FMT("001010dfffffff", "incf %F,%D"),
+ FMT("001011dfffffff", "decfsz %F,%D"),
+ FMT("001100dfffffff", "rrf %F,%D"),
+ FMT("001101dfffffff", "rlf %F,%D"),
+ FMT("001110dfffffff", "swapf %F,%D"),
+ FMT("001111dfffffff", "incfsz %F,%D"),
+ FMT("0100bbbfffffff", "bcf %F,%B"),
+ FMT("0101bbbfffffff", "bsf %F,%B"),
+ FMT("0110bbbfffffff", "btfsc %F,%B"),
+ FMT("0111bbbfffffff", "btfss %F,%B"),
+ FMT("1101xxkkkkkkkk", "retlw %K"),
+ FMT("100aaaaaaaaaaa", "call %A"),
+ FMT("101aaaaaaaaaaa", "goto %A"),
+ FMT("1100xxkkkkkkkk", "movlw %K"),
+ FMT("111000kkkkkkkk", "iorlw %K"),
+ FMT("111001kkkkkkkk", "andlw %K"),
+ FMT("111010kkkkkkkk", "xorlw %K"),
+ FMT("11110xkkkkkkkk", "sublw %K"),
+ FMT("11111xkkkkkkkk", "addlw %K"),
+ NULL
+};
+
+#define MAX_OPS (((sizeof(PIC16C62xFormats) / sizeof(PIC16C62xFormats[0])) - 1) / PTRS_PER_FORMAT)
+
+typedef struct opcode {
+ word mask; /* instruction mask */
+ word bits; /* constant bits */
+ word extcode; /* value that gets extension code */
+ const char *parse; /* how to parse bits */
+ const char *fmt; /* instruction format */
+} PIC16C62xOpcode;
+
+static PIC16C62xOpcode Op[MAX_OPS+1];
+static int OpInizialized = 0;
+
+static void InitDasm16C5x(void)
+{
+ const char *p;
+ const char *const *ops;
+ word mask, bits;
+ int bit;
+ int i;
+
+ ops = PIC16C62xFormats; i = 0;
+ while (*ops)
+ {
+ p = *ops;
+ mask = 0; bits = 0; bit = 13;
+ while (*p && bit >= 0)
+ {
+ switch (*p++)
+ {
+ case '1': mask |= 1<<bit; bits |= 1<<bit; bit--; break;
+ case '0': mask |= 1<<bit; bit--; break;
+ case ' ': break;
+ case 'a':
+ case 'b':
+ case 'd':
+ case 'f':
+ case 'k':
+ case 'x':
+ bit --;
+ break;
+ default: fatalerror("Invalid instruction encoding '%s %s'",
+ ops[0],ops[1]);
+ }
+ }
+ if (bit != -1 )
+ {
+ fatalerror("not enough bits in encoding '%s %s' %d",
+ ops[0],ops[1],bit);
+ }
+ while (isspace((UINT8)*p)) p++;
+ if (*p) Op[i].extcode = *p;
+ Op[i].bits = bits;
+ Op[i].mask = mask;
+ Op[i].fmt = ops[1];
+ Op[i].parse = ops[0];
+
+ ops += PTRS_PER_FORMAT;
+ i++;
+ }
+
+ OpInizialized = 1;
+}
+
+CPU_DISASSEMBLE( pic16c62x )
+{
+ int a, b, d, f, k; /* these can all be filled in by parsing an instruction */
+ int i;
+ int op;
+ int cnt = 1;
+ int code;
+ int bit;
+ char *buffertmp;
+ const char *cp; /* character pointer in OpFormats */
+ UINT32 flags = 0;
+
+ rombase = oprom;
+ rambase = opram;
+ pcbase = 2*pc;
+
+ if (!OpInizialized) InitDasm16C5x();
+
+ op = -1; /* no matching opcode */
+ code = READOP16(2*pc);
+ for ( i = 0; i < MAX_OPS; i++)
+ {
+ if ((code & Op[i].mask) == Op[i].bits)
+ {
+ if (op != -1)
+ {
+ mame_printf_debug("Error: opcode %04Xh matches %d (%s) and %d (%s)\n",
+ code,i,Op[i].fmt,op,Op[op].fmt);
+ }
+ op = i;
+ }
+ }
+ if (op == -1)
+ {
+ sprintf(buffer,"???? dw %04Xh",code);
+ return cnt;
+ }
+ buffertmp = buffer;
+ if (Op[op].extcode) /* Actually, theres no double length opcodes */
+ {
+ bit = 29;
+ code <<= 16;
+ code |= READARG16(2*(pc+cnt));
+ cnt++;
+ }
+ else
+ {
+ bit = 13;
+ }
+
+ /* shift out operands */
+ cp = Op[op].parse;
+ a = b = d = f = k = 0;
+
+ while (bit >= 0)
+ {
+ /* mame_printf_debug("{%c/%d}",*cp,bit); */
+ switch(*cp)
+ {
+ case 'a': a <<=1; a |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'b': b <<=1; b |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'd': d <<=1; d |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'f': f <<=1; f |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case 'k': k <<=1; k |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
+ case ' ': break;
+ case '1': case '0': case 'x': bit--; break;
+ case '\0': fatalerror("premature end of parse string, opcode %x, bit = %d",code,bit);
+ }
+ cp++;
+ }
+
+ /* now traverse format string */
+ cp = Op[op].fmt;
+ if (!strncmp(cp, "call", 4))
+ flags = DASMFLAG_STEP_OVER;
+ else if (!strncmp(cp, "ret", 3))
+ flags = DASMFLAG_STEP_OUT;
+
+ while (*cp)
+ {
+ if (*cp == '%')
+ {
+ char num[30], *q;
+ cp++;
+ switch (*cp++)
+ {
+ case 'A': sprintf(num,"$%03X",a); break;
+ case 'B': sprintf(num,"%d",b); break;
+ case 'D': sprintf(num,"%s",dest[d]); break;
+ case 'F': if (f < 0x20) sprintf(num,"%s",regfile[f]); else sprintf(num,"Reg$%02X",f); break;
+ case 'K': sprintf(num,"%02Xh",k); break;
+ default:
+ fatalerror("illegal escape character in format '%s'",Op[op].fmt);
+ }
+ q = num; while (*q) *buffer++ = *q++;
+ *buffer = '\0';
+ }
+ else
+ {
+ *buffer++ = *cp++;
+ *buffer = '\0';
+ }
+ }
+ return cnt | flags | DASMFLAG_SUPPORTED;
+}
diff --git a/src/emu/cpu/pic16c62x/dis16c62x.c b/src/emu/cpu/pic16c62x/dis16c62x.c
new file mode 100644
index 00000000000..b43765fa713
--- /dev/null
+++ b/src/emu/cpu/pic16c62x/dis16c62x.c
@@ -0,0 +1,136 @@
+ /**************************************************************************\
+ * Microchip PIC16C62X Emulator *
+ * *
+ * Based On *
+ * Microchip PIC16C5X Emulator *
+ * Copyright Tony La Porta *
+ * Originally written for the MAME project. *
+ * *
+ * *
+ * Notes : Data is expected to be read from source file as LSB first. *
+ * *
+ \**************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "16c62xdsm.c"
+
+
+unsigned char *Buffer;
+
+
+int main(int argc,char *argv[])
+{
+ int length=0, length_to_dump=0, offset=0, disasm_words=0;
+ int filelength=0, bytes_read;
+ int Counter=0;
+
+ FILE *F;
+ char *String_Output;
+
+ if(argc<2)
+ {
+ printf("\n");
+ printf("PIC16C5x Disassembler 1.0 by Tony La Porta (C)2003+\n\n");
+ printf("Usage: dis16c5x <input-file> [ <start-addr> [ <num-of-addr> ] ]\n");
+ printf(" <input-file> source file data must be MSB first\n");
+ printf(" <start-addr> starting address to disassemble from (decimal)\n");
+ printf(" <num-of-addr> number of addresses to disassemble (decimal)\n");
+ printf(" Preceed values with 0x if HEX values preffered\n");
+ exit(1);
+ }
+
+ if(!(F=fopen(argv[1],"rb")))
+ {
+ printf("\n%s: Can't open file %s\n",argv[0],argv[1]);
+ exit(2);
+ }
+ argv++; argc--;
+ if (argv[1])
+ {
+ offset = strtol(argv[1],NULL,0);
+ argv++; argc--;
+ }
+ if (argv[1])
+ {
+ length = strtol(argv[1],NULL,0);
+ argv++; argc--;
+ }
+
+ fseek(F,0, SEEK_END);
+ filelength = ftell(F);
+
+ length *= 2;
+
+ if ((length > (filelength - (offset*2))) || (length == 0)) length = filelength - (offset*2);
+ printf("Length=%04Xh(words) Offset=$%04Xh filelength=%04Xh(words) %04Xh(bytes)\n",length/2,offset,filelength/2,filelength);
+ length_to_dump = length;
+ printf("Starting from %d, dumping %d opcodes (word size)\n",offset,length/2);
+ Buffer = calloc((filelength+1),sizeof(char));
+ if (Buffer==NULL)
+ {
+ printf("Out of Memory !!!");
+ fclose(F);
+ exit(3);
+ }
+ String_Output = calloc(80,sizeof(char));
+ if (String_Output==NULL)
+ {
+ printf("Out of Memory !!!");
+ free(Buffer);
+ fclose(F);
+ exit(4);
+ }
+
+ if (fseek(F,0,SEEK_SET) != 0)
+ {
+ printf("Error seeking to beginning of file\n");
+ free(String_Output);
+ free(Buffer);
+ fclose(F);
+ exit(5);
+ }
+
+ Counter = offset;
+ bytes_read = fread(Buffer,sizeof(char),filelength,F);
+ if (bytes_read >= length)
+ {
+ for (; length > 0; length -= (disasm_words*2))
+ {
+ int ii;
+ disasm_words = Dasm16C5x(String_Output,Counter);
+ printf("$%03X: ",Counter);
+ for (ii = 0; ii < disasm_words; ii++)
+ {
+ if (((Counter*2) + ii) > filelength) /* Past end of length to dump ? */
+ {
+ sprintf(String_Output,"???? dw %02.2X%02.2Xh (Past end of disassembly !)",Buffer[((Counter-1)*2)+1],Buffer[((Counter-1)*2)]);
+ }
+ else
+ {
+ printf("%02.2x%02.2x ",Buffer[(Counter*2)+1],Buffer[(Counter*2)]);
+ }
+ Counter++ ;
+ }
+ for (; ii < 4; ii++)
+ {
+ printf(" ");
+ }
+ printf("\t%s\n",String_Output);
+ }
+ }
+ else
+ {
+ printf("ERROR length to dump was %d ", length_to_dump/2);
+ printf(", but bytes read from file were %d\n", bytes_read/2);
+ free(String_Output);
+ free(Buffer);
+ fclose(F);
+ exit(7);
+ }
+ free(String_Output);
+ free(Buffer);
+ fclose(F);
+ return(0);
+}
diff --git a/src/emu/cpu/pic16c62x/pic16c62x.c b/src/emu/cpu/pic16c62x/pic16c62x.c
new file mode 100644
index 00000000000..24c7a2c3eb8
--- /dev/null
+++ b/src/emu/cpu/pic16c62x/pic16c62x.c
@@ -0,0 +1,1607 @@
+ /**************************************************************************\
+ * Microchip PIC16C62X Emulator *
+ * *
+ * Based On *
+ * Microchip PIC16C5X Emulator *
+ * Copyright Tony La Porta *
+ * Originally written for the MAME project. *
+ * *
+ * *
+ * Addressing architecture is based on the Harvard addressing scheme. *
+ * *
+ * *
+ * **** Change Log **** *
+ * SZ (22-Oct-2009) *
+ * - Improvements and tests *
+ * SZ (2-Oct-2009) *
+ * - Internal ram and registers *
+ * SZ (12-Sep-2009) *
+ * - Started working on it. *
+ * *
+ * *
+ * **** TODO **** *
+ * - Finish checking opcodes/instructions *
+ * - Internal devices *
+ * - Interrupts *
+ * - Everything ! *
+ * *
+ * **** DONE **** *
+ * - I/O ports *
+ * - Savestates *
+ * - Internal memory *
+ * - New opcodes *
+ * - Opcode disassembly *
+ * *
+ * **** Notes (from PIC16C5X): **** *
+ * PIC WatchDog Timer has a seperate internal clock. For the moment, we're *
+ * basing the count on a 4MHz input clock, since 4MHz is the typical *
+ * input frequency (but by no means always). *
+ * A single scaler is available for the Counter/Timer or WatchDog Timer. *
+ * When connected to the Counter/Timer, it functions as a Prescaler, *
+ * hence prescale overflows, tick the Counter/Timer. *
+ * When connected to the WatchDog Timer, it functions as a Postscaler *
+ * hence WatchDog Timer overflows, tick the Postscaler. This scenario *
+ * means that the WatchDog timeout occurs when the Postscaler has *
+ * reached the scaler rate value, not when the WatchDog reaches zero. *
+ * CLRWDT should prevent the WatchDog Timer from timing out and generating *
+ * a device reset, but how is not known. The manual also mentions that *
+ * the WatchDog Timer can only be disabled during ROM programming, and *
+ * no other means seem to exist??? *
+ * *
+ \**************************************************************************/
+
+#include "debugger.h"
+#include "pic16c62x.h"
+
+
+
+
+typedef struct _pic16c62x_state pic16c62x_state;
+struct _pic16c62x_state
+{
+ /******************** CPU Internal Registers *******************/
+ UINT16 PC;
+ UINT16 PREVPC; /* previous program counter */
+ UINT8 W;
+ UINT8 PCLATH; /* 0a,8a */
+ UINT8 OPTION; /* 81 */
+ UINT16 CONFIG;
+ UINT8 ALU;
+ UINT16 WDT;
+ UINT8 TRISA; /* 85 */
+ UINT8 TRISB; /* 86 */
+ UINT16 STACK[8];
+ UINT16 prescaler; /* Note: this is really an 8-bit register */
+ PAIR opcode;
+ UINT8 *internalram;
+
+ int icount;
+ int reset_vector;
+ int picmodel;
+ int delay_timer;
+ UINT16 temp_config;
+ UINT8 old_T0;
+ INT8 old_data;
+ UINT8 picRAMmask;
+ int inst_cycles;
+
+
+ const device_config *device;
+ const address_space *program;
+ const address_space *data;
+ const address_space *io;
+};
+
+INLINE pic16c62x_state *get_safe_token(const device_config *device)
+{
+ assert(device != NULL);
+ assert(device->token != NULL);
+ assert(device->type == CPU);
+ assert(cpu_get_type(device) == CPU_PIC16C620 ||
+ cpu_get_type(device) == CPU_PIC16C620A ||
+// cpu_get_type(device) == CPU_PIC16CR620A ||
+ cpu_get_type(device) == CPU_PIC16C621 ||
+ cpu_get_type(device) == CPU_PIC16C621A ||
+ cpu_get_type(device) == CPU_PIC16C622 ||
+ cpu_get_type(device) == CPU_PIC16C622A);
+ return (pic16c62x_state *)device->token;
+}
+
+
+/* opcode table entry */
+typedef struct _pic16c62x_opcode pic16c62x_opcode;
+struct _pic16c62x_opcode
+{
+ UINT8 cycles;
+ void (*function)(pic16c62x_state *);
+};
+/* instruction list entry */
+typedef struct _pic16c62x_instruction pic16c62x_instruction;
+struct _pic16c62x_instruction
+{
+ char *format;
+ void (*function)(pic16c62x_state *);
+ UINT8 cycles;
+};
+
+
+INLINE void update_internalram_ptr(pic16c62x_state *cpustate)
+{
+ cpustate->internalram = (UINT8 *)memory_get_write_ptr(cpustate->data, 0x00);
+}
+
+#define PIC16C62x_RDOP(A) (memory_decrypted_read_word(cpustate->program, (A)<<1))
+#define PIC16C62x_RAM_RDMEM(A) ((UINT8)memory_read_byte_8le(cpustate->data, A))
+#define PIC16C62x_RAM_WRMEM(A,V) (memory_write_byte_8le(cpustate->data, A,V))
+#define PIC16C62x_In(Port) ((UINT8)memory_read_byte_8le(cpustate->io, (Port)))
+#define PIC16C62x_Out(Port,Value) (memory_write_byte_8le(cpustate->io, (Port),Value))
+/************ Read the state of the T0 Clock input signal ************/
+#define PIC16C62x_T0_In (memory_read_byte_8le(cpustate->io, PIC16C62x_T0) >> 4)
+
+#define M_RDRAM(A) (((A) == 0) ? cpustate->internalram[0] : PIC16C62x_RAM_RDMEM(A))
+#define M_WRTRAM(A,V) do { if ((A) == 0) cpustate->internalram[0] = (V); else PIC16C62x_RAM_WRMEM(A,V); } while (0)
+#define M_RDOP(A) PIC16C62x_RDOP(A)
+#define P_IN(A) PIC16C62x_In(A)
+#define P_OUT(A,V) PIC16C62x_Out(A,V)
+#define S_T0_IN PIC16C62x_T0_In
+#define ADDR_MASK 0x1fff
+
+
+
+#define TMR0 internalram[1]
+#define PCL internalram[2]
+#define STATUS internalram[3]
+#define FSR internalram[4]
+#define PORTA internalram[5]
+#define PORTB internalram[6]
+#define INDF M_RDRAM(cpustate->FSR)
+
+#define RISING_EDGE_T0 (( (int)(T0_in - cpustate->old_T0) > 0) ? 1 : 0)
+#define FALLING_EDGE_T0 (( (int)(T0_in - cpustate->old_T0) < 0) ? 1 : 0)
+
+
+/******** The following is the Status Flag register definition. *********/
+ /* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */
+ /* |IRP|RP1|RP0| TO | PD | Z | DC | C | */
+#define IRP_FLAG 0x80 /* IRP Register Bank Select bit (used for indirect addressing) */
+#define RP1_FLAG 0x40 /* RP1 Register Bank Select bits (used for direct addressing) */
+#define RP0_FLAG 0x20 /* RP0 Register Bank Select bits (used for direct addressing) */
+#define TO_FLAG 0x10 /* TO Time Out flag (WatchDog) */
+#define PD_FLAG 0x08 /* PD Power Down flag */
+#define Z_FLAG 0x04 /* Z Zero Flag */
+#define DC_FLAG 0x02 /* DC Digit Carry/Borrow flag (Nibble) */
+#define C_FLAG 0x01 /* C Carry/Borrow Flag (Byte) */
+
+#define IRP (cpustate->STATUS & IRP_FLAG)
+#define RP1 (cpustate->STATUS & RP1_FLAG)
+#define RP0 (cpustate->STATUS & RP0_FLAG)
+#define TO (cpustate->STATUS & TO_FLAG)
+#define PD (cpustate->STATUS & PD_FLAG)
+#define ZERO (cpustate->STATUS & Z_FLAG)
+#define DC (cpustate->STATUS & DC_FLAG)
+#define CARRY (cpustate->STATUS & C_FLAG)
+
+#define ADDR ((cpustate->opcode.b.l & 0x7f) | (RP0 << 2))
+
+/******** The following is the Option Flag register definition. *********/
+ /* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */
+ /* | RBPU | INTEDG | TOCS | TOSE | PSA | PS | */
+#define RBPU_FLAG 0x80 /* RBPU Pull-up Enable */
+#define INTEDG_FLAG 0x40 /* INTEDG Interrupt Edge Select */
+#define T0CS_FLAG 0x20 /* TOCS Timer 0 clock source select */
+#define T0SE_FLAG 0x10 /* TOSE Timer 0 clock source edge select */
+#define PSA_FLAG 0x08 /* PSA Prescaler Assignment bit */
+#define PS_REG 0x07 /* PS Prescaler Rate select */
+
+#define T0CS (cpustate->OPTION & T0CS_FLAG)
+#define T0SE (cpustate->OPTION & T0SE_FLAG)
+#define PSA (cpustate->OPTION & PSA_FLAG)
+#define PS (cpustate->OPTION & PS_REG)
+
+/******** The following is the Config Flag register definition. *********/
+ /* | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */
+ /* | CP | | BODEN | CP | PWRTE | WDTE | FOSC | */
+ /* CP Code Protect (ROM read protect) */
+#define BODEN_FLAG 0x40 /* BODEN Brown-out Reset Enable */
+#define PWRTE_FLAG 0x08 /* PWRTE Power-up Timer Enable */
+#define WDTE_FLAG 0x04 /* WDTE WatchDog Timer enable */
+#define FOSC_FLAG 0x03 /* FOSC Oscillator source select */
+
+#define WDTE (cpustate->CONFIG & WDTE_FLAG)
+#define FOSC (cpustate->CONFIG & FOSC_FLAG)
+
+
+/************************************************************************
+ * Shortcuts
+ ************************************************************************/
+
+#define CLR(flagreg, flag) ( flagreg &= (UINT8)(~flag) )
+#define SET(flagreg, flag) ( flagreg |= flag )
+
+
+/* Easy bit position selectors */
+#define POS ((cpustate->opcode.w.l >> 7) & 7)
+static const unsigned int bit_clr[8] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f };
+static const unsigned int bit_set[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
+
+
+
+INLINE void CALCULATE_Z_FLAG(pic16c62x_state *cpustate)
+{
+ if (cpustate->ALU == 0) SET(cpustate->STATUS, Z_FLAG);
+ else CLR(cpustate->STATUS, Z_FLAG);
+}
+
+INLINE void CALCULATE_ADD_CARRY(pic16c62x_state *cpustate)
+{
+ if ((UINT8)(cpustate->old_data) > (UINT8)(cpustate->ALU)) {
+ SET(cpustate->STATUS, C_FLAG);
+ }
+ else {
+ CLR(cpustate->STATUS, C_FLAG);
+ }
+}
+
+INLINE void CALCULATE_ADD_DIGITCARRY(pic16c62x_state *cpustate)
+{
+ if (((UINT8)(cpustate->old_data) & 0x0f) > ((UINT8)(cpustate->ALU) & 0x0f)) {
+ SET(cpustate->STATUS, DC_FLAG);
+ }
+ else {
+ CLR(cpustate->STATUS, DC_FLAG);
+ }
+}
+
+INLINE void CALCULATE_SUB_CARRY(pic16c62x_state *cpustate)
+{
+ if ((UINT8)(cpustate->old_data) < (UINT8)(cpustate->ALU)) {
+ CLR(cpustate->STATUS, C_FLAG);
+ }
+ else {
+ SET(cpustate->STATUS, C_FLAG);
+ }
+}
+
+INLINE void CALCULATE_SUB_DIGITCARRY(pic16c62x_state *cpustate)
+{
+ if (((UINT8)(cpustate->old_data) & 0x0f) < ((UINT8)(cpustate->ALU) & 0x0f)) {
+ CLR(cpustate->STATUS, DC_FLAG);
+ }
+ else {
+ SET(cpustate->STATUS, DC_FLAG);
+ }
+}
+
+
+
+INLINE UINT16 POP_STACK(pic16c62x_state *cpustate)
+{
+ UINT16 data = cpustate->STACK[7];
+ cpustate->STACK[7] = cpustate->STACK[6];
+ cpustate->STACK[6] = cpustate->STACK[5];
+ cpustate->STACK[5] = cpustate->STACK[4];
+ cpustate->STACK[4] = cpustate->STACK[3];
+ cpustate->STACK[3] = cpustate->STACK[2];
+ cpustate->STACK[2] = cpustate->STACK[1];
+ cpustate->STACK[1] = cpustate->STACK[0];
+ return (data & ADDR_MASK);
+}
+INLINE void PUSH_STACK(pic16c62x_state *cpustate, UINT16 data)
+{
+ cpustate->STACK[0] = cpustate->STACK[1];
+ cpustate->STACK[1] = cpustate->STACK[2];
+ cpustate->STACK[2] = cpustate->STACK[3];
+ cpustate->STACK[3] = cpustate->STACK[4];
+ cpustate->STACK[4] = cpustate->STACK[5];
+ cpustate->STACK[5] = cpustate->STACK[6];
+ cpustate->STACK[6] = cpustate->STACK[7];
+ cpustate->STACK[7] = (data & ADDR_MASK);
+}
+
+
+
+INLINE UINT8 GET_REGFILE(pic16c62x_state *cpustate, offs_t addr) /* Read from internal memory */
+{
+ UINT8 data;
+
+ if (addr == 0) { /* Indirect addressing */
+ addr = (cpustate->FSR & cpustate->picRAMmask);
+ }
+
+ switch(addr)
+ {
+ case 0x00: /* Not an actual register, so return 0 */
+ case 0x80:
+ data = 0;
+ break;
+ case 0x02:
+ case 0x03:
+ case 0x0b:
+ case 0x82:
+ case 0x83:
+ case 0x8b:
+ data = M_RDRAM(addr & 0x7f);
+ break;
+ case 0x84:
+ case 0x04: data = (cpustate->FSR | (UINT8)(~cpustate->picRAMmask));
+ break;
+ case 0x05: data = P_IN(0);
+ data &= cpustate->TRISA;
+ data |= ((UINT8)(~cpustate->TRISA) & cpustate->PORTA);
+ data &= 0x1f; /* 5-bit port (only lower 5 bits used) */
+ break;
+ case 0x06: data = P_IN(1);
+ data &= cpustate->TRISB;
+ data |= ((UINT8)(~cpustate->TRISB) & cpustate->PORTB);
+ break;
+ case 0x8a:
+ case 0x0a: data = cpustate->PCLATH;
+ break;
+ case 0x81: data = cpustate->OPTION;
+ break;
+ case 0x85: data = cpustate->TRISA;
+ break;
+ case 0x86: data = cpustate->TRISB;
+ break;
+ default: data = M_RDRAM(addr);
+ break;
+ }
+ return data;
+}
+
+INLINE void STORE_REGFILE(pic16c62x_state *cpustate, offs_t addr, UINT8 data) /* Write to internal memory */
+{
+ if (addr == 0) { /* Indirect addressing */
+ addr = (cpustate->FSR & cpustate->picRAMmask);
+ }
+
+ switch(addr)
+ {
+ case 0x80:
+ case 0x00: /* Not an actual register, nothing to save */
+ break;
+ case 0x01: cpustate->delay_timer = 2; /* Timer starts after next two instructions */
+ if (PSA == 0) cpustate->prescaler = 0; /* Must clear the Prescaler */
+ cpustate->TMR0 = data;
+ break;
+ case 0x82:
+ case 0x02: cpustate->PCL = data;
+ cpustate->PC = (cpustate->PCLATH << 8) | data;
+ break;
+ case 0x83:
+ case 0x03: cpustate->STATUS &= (UINT8)(~(IRP_FLAG|RP1_FLAG|RP0_FLAG)); cpustate->STATUS |= (data & (IRP_FLAG|RP1_FLAG|RP0_FLAG));
+ break;
+ case 0x84:
+ case 0x04: cpustate->FSR = (data | (UINT8)(~cpustate->picRAMmask));
+ break;
+ case 0x05: data &= 0x1f; /* 5-bit port (only lower 5 bits used) */
+ P_OUT(0,data & (UINT8)(~cpustate->TRISA)); cpustate->PORTA = data;
+ break;
+ case 0x06: P_OUT(1,data & (UINT8)(~cpustate->TRISB)); cpustate->PORTB = data;
+ break;
+ case 0x8a:
+ case 0x0a:
+ cpustate->PCLATH = data & 0x1f;
+ M_WRTRAM(0x0a, cpustate->PCLATH);
+ break;
+ case 0x8b:
+ case 0x0b: M_WRTRAM(0x0b, data);
+ break;
+ case 0x81: cpustate->OPTION = data;
+ M_WRTRAM(0x81, data);
+ break;
+ case 0x85: if (cpustate->TRISA != data)
+ {
+ cpustate->TRISA = data | 0xf0;
+ P_OUT(2,cpustate->TRISA);
+ P_OUT(0,cpustate->PORTA & (UINT8)(~cpustate->TRISA) & 0x0f);
+ M_WRTRAM(addr, data);
+ }
+ break;
+ case 0x86: if (cpustate->TRISB != data)
+ {
+ cpustate->TRISB = data;
+ P_OUT(3,cpustate->TRISB);
+ P_OUT(1,cpustate->PORTB & (UINT8)(~cpustate->TRISB));
+ M_WRTRAM(addr, data);
+ }
+ break;
+ default: M_WRTRAM(addr, data);
+ break;
+ }
+}
+
+
+INLINE void STORE_RESULT(pic16c62x_state *cpustate, offs_t addr, UINT8 data)
+{
+ if (cpustate->opcode.b.l & 0x80)
+ {
+ STORE_REGFILE(cpustate, addr, data);
+ }
+ else
+ {
+ cpustate->W = data;
+ }
+}
+
+
+/************************************************************************
+ * Emulate the Instructions
+ ************************************************************************/
+
+/* This following function is here to fill in the void for */
+/* the opcode call function. This function is never called. */
+
+
+static void illegal(pic16c62x_state *cpustate)
+{
+ logerror("PIC16C62x: PC=%03x, Illegal opcode = %04x\n", (cpustate->PC-1), cpustate->opcode.w.l);
+}
+
+
+static void addwf(pic16c62x_state *cpustate)
+{
+ cpustate->old_data = GET_REGFILE(cpustate, ADDR);
+ cpustate->ALU = cpustate->old_data + cpustate->W;
+ STORE_RESULT(cpustate, ADDR, cpustate->ALU);
+ CALCULATE_Z_FLAG(cpustate);
+ CALCULATE_ADD_CARRY(cpustate);
+ CALCULATE_ADD_DIGITCARRY(cpustate);
+}
+
+static void addlw(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = (cpustate->opcode.b.l & 0xff) + cpustate->W;
+ cpustate->W = cpustate->ALU;
+ CALCULATE_Z_FLAG(cpustate);
+ CALCULATE_ADD_CARRY(cpustate);
+ CALCULATE_ADD_DIGITCARRY(cpustate);
+}
+
+static void andwf(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = GET_REGFILE(cpustate, ADDR) & cpustate->W;
+ STORE_RESULT(cpustate, ADDR, cpustate->ALU);
+ CALCULATE_Z_FLAG(cpustate);
+}
+
+static void andlw(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = cpustate->opcode.b.l & cpustate->W;
+ cpustate->W = cpustate->ALU;
+ CALCULATE_Z_FLAG(cpustate);
+}
+
+static void bcf(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = GET_REGFILE(cpustate, ADDR);
+ cpustate->ALU &= bit_clr[POS];
+ STORE_REGFILE(cpustate, ADDR, cpustate->ALU);
+}
+
+static void bsf(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = GET_REGFILE(cpustate, ADDR);
+ cpustate->ALU |= bit_set[POS];
+ STORE_REGFILE(cpustate, ADDR, cpustate->ALU);
+}
+
+static void btfss(pic16c62x_state *cpustate)
+{
+ if ((GET_REGFILE(cpustate, ADDR) & bit_set[POS]) == bit_set[POS])
+ {
+ cpustate->PC++ ;
+ cpustate->PCL = cpustate->PC & 0xff;
+ cpustate->inst_cycles += 1; /* Add NOP cycles */
+ }
+}
+
+static void btfsc(pic16c62x_state *cpustate)
+{
+ if ((GET_REGFILE(cpustate, ADDR) & bit_set[POS]) == 0)
+ {
+ cpustate->PC++ ;
+ cpustate->PCL = cpustate->PC & 0xff;
+ cpustate->inst_cycles += 1; /* Add NOP cycles */
+ }
+}
+
+static void call(pic16c62x_state *cpustate)
+{
+ PUSH_STACK(cpustate, cpustate->PC);
+ cpustate->PC = ((cpustate->PCLATH & 0x18) << 8) | (cpustate->opcode.w.l & 0x7ff);
+ cpustate->PC &= ADDR_MASK;
+ cpustate->PCL = cpustate->PC & 0xff;
+}
+
+static void clrw(pic16c62x_state *cpustate)
+{
+ cpustate->W = 0;
+ SET(cpustate->STATUS, Z_FLAG);
+}
+
+static void clrf(pic16c62x_state *cpustate)
+{
+ STORE_REGFILE(cpustate, ADDR, 0);
+ SET(cpustate->STATUS, Z_FLAG);
+}
+
+static void clrwdt(pic16c62x_state *cpustate)
+{
+ cpustate->WDT = 0;
+ if (PSA) cpustate->prescaler = 0;
+ SET(cpustate->STATUS, TO_FLAG);
+ SET(cpustate->STATUS, PD_FLAG);
+}
+
+static void comf(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = (UINT8)(~(GET_REGFILE(cpustate, ADDR)));
+ STORE_RESULT(cpustate, ADDR, cpustate->ALU);
+ CALCULATE_Z_FLAG(cpustate);
+}
+
+static void decf(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = GET_REGFILE(cpustate, ADDR) - 1;
+ STORE_RESULT(cpustate, ADDR, cpustate->ALU);
+ CALCULATE_Z_FLAG(cpustate);
+}
+
+static void decfsz(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = GET_REGFILE(cpustate, ADDR) - 1;
+ STORE_RESULT(cpustate, ADDR, cpustate->ALU);
+ if (cpustate->ALU == 0)
+ {
+ cpustate->PC++ ;
+ cpustate->PCL = cpustate->PC & 0xff;
+ cpustate->inst_cycles += 1; /* Add NOP cycles */
+ }
+}
+
+static void goto_op(pic16c62x_state *cpustate)
+{
+ cpustate->PC = ((cpustate->PCLATH & 0x18) << 8) | (cpustate->opcode.w.l & 0x7ff);
+ cpustate->PC &= ADDR_MASK;
+ cpustate->PCL = cpustate->PC & 0xff;
+}
+
+static void incf(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = GET_REGFILE(cpustate, ADDR) + 1;
+ STORE_RESULT(cpustate, ADDR, cpustate->ALU);
+ CALCULATE_Z_FLAG(cpustate);
+}
+
+static void incfsz(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = GET_REGFILE(cpustate, ADDR) + 1;
+ STORE_RESULT(cpustate, ADDR, cpustate->ALU);
+ if (cpustate->ALU == 0)
+ {
+ cpustate->PC++ ;
+ cpustate->PCL = cpustate->PC & 0xff;
+ cpustate->inst_cycles += 1; /* Add NOP cycles */
+ }
+}
+
+static void iorlw(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = cpustate->opcode.b.l | cpustate->W;
+ cpustate->W = cpustate->ALU;
+ CALCULATE_Z_FLAG(cpustate);
+}
+
+static void iorwf(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = GET_REGFILE(cpustate, ADDR) | cpustate->W;
+ STORE_RESULT(cpustate, ADDR, cpustate->ALU);
+ CALCULATE_Z_FLAG(cpustate);
+}
+
+static void movf(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = GET_REGFILE(cpustate, ADDR);
+ STORE_RESULT(cpustate, ADDR, cpustate->ALU);
+ CALCULATE_Z_FLAG(cpustate);
+}
+
+static void movlw(pic16c62x_state *cpustate)
+{
+ cpustate->W = cpustate->opcode.b.l;
+}
+
+static void movwf(pic16c62x_state *cpustate)
+{
+ STORE_REGFILE(cpustate, ADDR, cpustate->W);
+}
+
+static void nop(pic16c62x_state *cpustate)
+{
+ /* Do nothing */
+}
+
+static void option(pic16c62x_state *cpustate)
+{
+ cpustate->OPTION = cpustate->W;
+}
+
+static void retlw(pic16c62x_state *cpustate)
+{
+ cpustate->W = cpustate->opcode.b.l;
+ cpustate->PC = POP_STACK(cpustate);
+ cpustate->PCL = cpustate->PC & 0xff;
+}
+
+static void returns(pic16c62x_state *cpustate)
+{
+ cpustate->PC = POP_STACK(cpustate);
+ cpustate->PCL = cpustate->PC & 0xff;
+}
+
+static void retfie(pic16c62x_state *cpustate)
+{
+ cpustate->PC = POP_STACK(cpustate);
+ cpustate->PCL = cpustate->PC & 0xff;
+ //INTCON(7)=1;
+}
+
+static void rlf(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = GET_REGFILE(cpustate, ADDR);
+ cpustate->ALU <<= 1;
+ if (cpustate->STATUS & C_FLAG) cpustate->ALU |= 1;
+ if (GET_REGFILE(cpustate, ADDR) & 0x80) SET(cpustate->STATUS, C_FLAG);
+ else CLR(cpustate->STATUS, C_FLAG);
+ STORE_RESULT(cpustate, ADDR, cpustate->ALU);
+}
+
+static void rrf(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = GET_REGFILE(cpustate, ADDR);
+ cpustate->ALU >>= 1;
+ if (cpustate->STATUS & C_FLAG) cpustate->ALU |= 0x80;
+ if (GET_REGFILE(cpustate, ADDR) & 1) SET(cpustate->STATUS, C_FLAG);
+ else CLR(cpustate->STATUS, C_FLAG);
+ STORE_RESULT(cpustate, ADDR, cpustate->ALU);
+}
+
+static void sleepic(pic16c62x_state *cpustate)
+{
+ if (WDTE) cpustate->WDT = 0;
+ if (PSA) cpustate->prescaler = 0;
+ SET(cpustate->STATUS, TO_FLAG);
+ CLR(cpustate->STATUS, PD_FLAG);
+}
+
+static void subwf(pic16c62x_state *cpustate)
+{
+ cpustate->old_data = GET_REGFILE(cpustate, ADDR);
+ cpustate->ALU = cpustate->old_data - cpustate->W;
+ STORE_RESULT(cpustate, ADDR, cpustate->ALU);
+ CALCULATE_Z_FLAG(cpustate);
+ CALCULATE_SUB_CARRY(cpustate);
+ CALCULATE_SUB_DIGITCARRY(cpustate);
+}
+
+static void sublw(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = (cpustate->opcode.b.l & 0xff) - cpustate->W;
+ cpustate->W = cpustate->ALU;
+ CALCULATE_Z_FLAG(cpustate);
+ CALCULATE_SUB_CARRY(cpustate);
+ CALCULATE_SUB_DIGITCARRY(cpustate);
+}
+
+static void swapf(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = ((GET_REGFILE(cpustate, ADDR) << 4) & 0xf0);
+ cpustate->ALU |= ((GET_REGFILE(cpustate, ADDR) >> 4) & 0x0f);
+ STORE_RESULT(cpustate, ADDR, cpustate->ALU);
+}
+
+static void tris(pic16c62x_state *cpustate)
+{
+
+ switch(cpustate->opcode.b.l & 0x7)
+ {
+ case 05: STORE_REGFILE(cpustate, 0x85, cpustate->W); break;
+ case 06: STORE_REGFILE(cpustate, 0x86, cpustate->W); break;
+ default: illegal(cpustate); break;
+ }
+}
+
+static void xorlw(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = cpustate->W ^ cpustate->opcode.b.l;
+ cpustate->W = cpustate->ALU;
+ CALCULATE_Z_FLAG(cpustate);
+}
+
+static void xorwf(pic16c62x_state *cpustate)
+{
+ cpustate->ALU = GET_REGFILE(cpustate, ADDR) ^ cpustate->W;
+ STORE_RESULT(cpustate, ADDR, cpustate->ALU);
+ CALCULATE_Z_FLAG(cpustate);
+}
+
+
+/***********************************************************************
+ * Instruction Table (Format, Instruction, Cycles)
+ ***********************************************************************/
+
+static const pic16c62x_instruction instructiontable[]=
+{
+ {(char *)"000111dfffffff", addwf, 1},
+ {(char *)"000101dfffffff", andwf, 1},
+ {(char *)"0000011fffffff", clrf, 1},
+ {(char *)"00000100000011", clrw, 1},
+ {(char *)"001001dfffffff", comf, 1},
+ {(char *)"000011dfffffff", decf, 1},
+ {(char *)"001011dfffffff", decfsz, 1},
+ {(char *)"001010dfffffff", incf, 1},
+ {(char *)"001111dfffffff", incfsz, 1},
+ {(char *)"000100dfffffff", iorwf, 1},
+ {(char *)"001000dfffffff", movf, 1},
+ {(char *)"0000001fffffff", movwf, 1},
+ {(char *)"0000000xx00000", nop, 1},
+ {(char *)"001101dfffffff", rlf, 1},
+ {(char *)"001100dfffffff", rrf, 1},
+ {(char *)"000010dfffffff", subwf, 1},
+ {(char *)"001110dfffffff", swapf, 1},
+ {(char *)"000110dfffffff", xorwf, 1},
+ {(char *)"0100bbbfffffff", bcf, 1},
+ {(char *)"0101bbbfffffff", bsf, 1},
+ {(char *)"0110bbbfffffff", btfsc, 1},
+ {(char *)"0111bbbfffffff", btfss, 1},
+ {(char *)"11111xkkkkkkkk", addlw, 1},
+ {(char *)"111001kkkkkkkk", andlw, 1},
+ {(char *)"100aaaaaaaaaaa", call, 2},
+ {(char *)"101aaaaaaaaaaa", goto_op, 2},
+ {(char *)"111000kkkkkkkk", iorlw, 1},
+ {(char *)"1100xxkkkkkkkk", movlw, 1},
+ {(char *)"00000000001001", retfie, 2},
+ {(char *)"1101xxkkkkkkkk", retlw, 2},
+ {(char *)"00000000001000", returns, 2},
+ {(char *)"00000001100011", sleepic, 1},
+ {(char *)"11110xkkkkkkkk", sublw, 1},
+ {(char *)"111010kkkkkkkk", xorlw, 1},
+ {(char *)"00000001100100", clrwdt, 1},
+ {(char *)"00000001100010", option, 1}, // deprecated
+ {(char *)"00000001100fff", tris, 1}, // deprecated
+ {NULL, NULL, 0}
+};
+
+/***********************************************************************
+ * Opcode Table (Cycles, Instruction)
+ ***********************************************************************/
+
+static pic16c62x_opcode opcode_table[16384];
+
+/***********************************************************************
+ * Opcode Table build function
+ ***********************************************************************/
+
+static void build_opcode_table(void)
+{
+int instr,mask,bits;
+int a;
+
+ // defaults
+ for ( a = 0; a < 16384; a++)
+ {
+ opcode_table[a].cycles = 0;
+ opcode_table[a].function = illegal;
+ }
+ // build table
+ for( instr = 0; instructiontable[instr].cycles != 0; instr++)
+ {
+ bits=0;
+ mask=0;
+ for ( a = 0; a < 14; a++)
+ {
+ switch (instructiontable[instr].format[a])
+ {
+ case '0':
+ bits = bits << 1;
+ mask = (mask << 1) | 1;
+ break;
+ case '1':
+ bits = (bits << 1) | 1;
+ mask = (mask << 1) | 1;
+ break;
+ default:
+ bits = bits << 1;
+ mask = mask << 1;
+ break;
+ }
+ }
+ for ( a = 0; a < 16384; a++)
+ {
+ if (((a & mask) == bits) && (opcode_table[a].cycles == 0))
+ {
+ opcode_table[a].cycles = instructiontable[instr].cycles;
+ opcode_table[a].function = instructiontable[instr].function;
+ }
+ }
+ }
+}
+
+/****************************************************************************
+ * Inits CPU emulation
+ ****************************************************************************/
+
+static CPU_INIT( pic16c62x )
+{
+ pic16c62x_state *cpustate = get_safe_token(device);
+
+ cpustate->device = device;
+ cpustate->program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM);
+ cpustate->data = memory_find_address_space(device, ADDRESS_SPACE_DATA);
+ cpustate->io = memory_find_address_space(device, ADDRESS_SPACE_IO);
+
+ cpustate->CONFIG = 0x3fff;
+
+ /* ensure the internal ram pointers are set before get_info is called */
+ update_internalram_ptr(cpustate);
+
+ build_opcode_table();
+
+ state_save_register_device_item(device, 0, cpustate->W);
+ state_save_register_device_item(device, 0, cpustate->ALU);
+ state_save_register_device_item(device, 0, cpustate->OPTION);
+ state_save_register_device_item(device, 0, cpustate->PCLATH);
+ state_save_register_device_item(device, 0, cpustate->TMR0);
+ state_save_register_device_item(device, 0, cpustate->PCL);
+ state_save_register_device_item(device, 0, cpustate->STATUS);
+ state_save_register_device_item(device, 0, cpustate->FSR);
+ state_save_register_device_item(device, 0, cpustate->PORTA);
+ state_save_register_device_item(device, 0, cpustate->PORTB);
+ state_save_register_device_item(device, 0, cpustate->TRISA);
+ state_save_register_device_item(device, 0, cpustate->TRISB);
+ state_save_register_device_item(device, 0, cpustate->old_T0);
+ state_save_register_device_item(device, 0, cpustate->old_data);
+ state_save_register_device_item(device, 0, cpustate->picRAMmask);
+ state_save_register_device_item(device, 0, cpustate->WDT);
+ state_save_register_device_item(device, 0, cpustate->prescaler);
+ state_save_register_device_item(device, 0, cpustate->STACK[0]);
+ state_save_register_device_item(device, 0, cpustate->STACK[1]);
+ state_save_register_device_item(device, 0, cpustate->STACK[2]);
+ state_save_register_device_item(device, 0, cpustate->STACK[3]);
+ state_save_register_device_item(device, 0, cpustate->STACK[4]);
+ state_save_register_device_item(device, 0, cpustate->STACK[5]);
+ state_save_register_device_item(device, 0, cpustate->STACK[6]);
+ state_save_register_device_item(device, 0, cpustate->STACK[7]);
+ state_save_register_device_item(device, 0, cpustate->PC);
+ state_save_register_device_item(device, 0, cpustate->PREVPC);
+ state_save_register_device_item(device, 0, cpustate->CONFIG);
+ state_save_register_device_item(device, 0, cpustate->opcode.d);
+ state_save_register_device_item(device, 0, cpustate->delay_timer);
+ state_save_register_device_item(device, 0, cpustate->picmodel);
+ state_save_register_device_item(device, 0, cpustate->reset_vector);
+
+ state_save_register_device_item(device, 0, cpustate->icount);
+ state_save_register_device_item(device, 0, cpustate->temp_config);
+ state_save_register_device_item(device, 0, cpustate->inst_cycles);
+}
+
+
+/****************************************************************************
+ * Reset registers to their initial values
+ ****************************************************************************/
+
+static void pic16c62x_reset_regs(pic16c62x_state *cpustate)
+{
+ cpustate->PC = cpustate->reset_vector;
+ cpustate->TRISA = 0x1f;
+ cpustate->TRISB = 0xff;
+ cpustate->OPTION = 0xff;
+ cpustate->STATUS = 0x18;
+ cpustate->PCL = 0;
+ cpustate->FSR |= (UINT8)(~cpustate->picRAMmask);
+ cpustate->PORTA = 0;
+ cpustate->prescaler = 0;
+ cpustate->delay_timer = 0;
+ cpustate->old_T0 = 0;
+ cpustate->inst_cycles = 0;
+ PIC16C62x_RAM_WRMEM(0x85,cpustate->TRISA);
+ PIC16C62x_RAM_WRMEM(0x86,cpustate->TRISB);
+ PIC16C62x_RAM_WRMEM(0x81,cpustate->OPTION);
+}
+
+static void pic16c62x_soft_reset(pic16c62x_state *cpustate)
+{
+ SET(cpustate->STATUS, (TO_FLAG | PD_FLAG | Z_FLAG | DC_FLAG | C_FLAG));
+ pic16c62x_reset_regs(cpustate);
+}
+
+void pic16c62x_set_config(const device_config *cpu, int data)
+{
+ pic16c62x_state *cpustate = get_safe_token(cpu);
+
+ logerror("Writing %04x to the PIC16C62x configuration bits\n",data);
+ cpustate->CONFIG = (data & 0x3fff);
+}
+
+
+/****************************************************************************
+ * Shut down CPU emulation
+ ****************************************************************************/
+
+static CPU_EXIT( pic16c62x )
+{
+ /* nothing to do */
+}
+
+
+/****************************************************************************
+ * WatchDog
+ ****************************************************************************/
+
+static void pic16c62x_update_watchdog(pic16c62x_state *cpustate, int counts)
+{
+ /* TODO: needs updating */
+ /* WatchDog is set up to count 18,000 (0x464f hex) ticks to provide */
+ /* the timeout period of 0.018ms based on a 4MHz input clock. */
+ /* Note: the 4MHz clock should be divided by the PIC16C5x_CLOCK_DIVIDER */
+ /* which effectively makes the PIC run at 1MHz internally. */
+
+ /* If the current instruction is CLRWDT or SLEEP, don't update the WDT */
+
+ if ((cpustate->opcode.w.l != 0x64) && (cpustate->opcode.w.l != 0x63))
+ {
+ UINT16 old_WDT = cpustate->WDT;
+
+ cpustate->WDT -= counts;
+
+ if (cpustate->WDT > 0x464f) {
+ cpustate->WDT = 0x464f - (0xffff - cpustate->WDT);
+ }
+
+ if (((old_WDT != 0) && (old_WDT < cpustate->WDT)) || (cpustate->WDT == 0))
+ {
+ if (PSA) {
+ cpustate->prescaler++;
+ if (cpustate->prescaler >= (1 << PS)) { /* Prescale values from 1 to 128 */
+ cpustate->prescaler = 0;
+ CLR(cpustate->STATUS, TO_FLAG);
+ pic16c62x_soft_reset(cpustate);
+ }
+ }
+ else {
+ CLR(cpustate->STATUS, TO_FLAG);
+ pic16c62x_soft_reset(cpustate);
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ * Update Timer
+ ****************************************************************************/
+
+static void pic16c62x_update_timer(pic16c62x_state *cpustate, int counts)
+{
+ if (PSA == 0) {
+ cpustate->prescaler += counts;
+ if (cpustate->prescaler >= (2 << PS)) { /* Prescale values from 2 to 256 */
+ cpustate->TMR0 += (cpustate->prescaler / (2 << PS));
+ cpustate->prescaler %= (2 << PS); /* Overflow prescaler */
+ }
+ }
+ else {
+ cpustate->TMR0 += counts;
+ }
+}
+
+
+/****************************************************************************
+ * Execute IPeriod. Return 0 if emulation should be stopped
+ ****************************************************************************/
+
+static CPU_EXECUTE( pic16c62x )
+{
+ pic16c62x_state *cpustate = get_safe_token(device);
+ UINT8 T0_in;
+
+ update_internalram_ptr(cpustate);
+
+ cpustate->icount = cycles;
+
+ do
+ {
+ if (PD == 0) /* Sleep Mode */
+ {
+ cpustate->inst_cycles = 1;
+ debugger_instruction_hook(device, cpustate->PC);
+ if (WDTE) {
+ pic16c62x_update_watchdog(cpustate, 1);
+ }
+ }
+ else
+ {
+ cpustate->PREVPC = cpustate->PC;
+
+ debugger_instruction_hook(device, cpustate->PC);
+
+ cpustate->opcode.d = M_RDOP(cpustate->PC);
+ cpustate->PC++;
+ cpustate->PCL++;
+
+ cpustate->inst_cycles = opcode_table[cpustate->opcode.w.l & 16383].cycles;
+ (*opcode_table[cpustate->opcode.w.l & 16383].function)(cpustate);
+
+ if (T0CS) { /* Count mode */
+ T0_in = S_T0_IN;
+ if (T0_in) T0_in = 1;
+ if (T0SE) { /* Count falling edge T0 input */
+ if (FALLING_EDGE_T0) {
+ pic16c62x_update_timer(cpustate, 1);
+ }
+ }
+ else { /* Count rising edge T0 input */
+ if (RISING_EDGE_T0) {
+ pic16c62x_update_timer(cpustate, 1);
+ }
+ }
+ cpustate->old_T0 = T0_in;
+ }
+ else { /* Timer mode */
+ if (cpustate->delay_timer) {
+ cpustate->delay_timer--;
+ }
+ else {
+ pic16c62x_update_timer(cpustate, cpustate->inst_cycles);
+ }
+ }
+ if (WDTE) {
+ pic16c62x_update_watchdog(cpustate, cpustate->inst_cycles);
+ }
+ }
+
+ cpustate->icount -= cpustate->inst_cycles;
+
+ } while (cpustate->icount > 0);
+
+ return cycles - cpustate->icount;
+}
+
+
+
+/**************************************************************************
+ * Generic set_info
+ **************************************************************************/
+
+static CPU_SET_INFO( pic16c62x )
+{
+ pic16c62x_state *cpustate = get_safe_token(device);
+
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + PIC16C62x_PC: cpustate->PC = info->i; cpustate->PCL = info->i & 0xff ;break;
+ /* This is actually not a stack pointer, but the stack contents */
+ /* Stack is a 8 level First In Last Out stack */
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK7: cpustate->STACK[7] = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK6: cpustate->STACK[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK5: cpustate->STACK[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK4: cpustate->STACK[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK3: cpustate->STACK[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK2: cpustate->STACK[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK1: cpustate->STACK[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK0: cpustate->STACK[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_W: cpustate->W = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_ALU: cpustate->ALU = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_OPT: cpustate->OPTION = info->i & (RBPU_FLAG | INTEDG_FLAG | T0CS_FLAG | T0SE_FLAG | PSA_FLAG | PS_REG); break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_TMR0: cpustate->TMR0 = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_WDT: cpustate->WDT = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_PSCL: cpustate->prescaler = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_PRTA: cpustate->PORTA = info->i & 0x1f; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_PRTB: cpustate->PORTB = info->i; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_FSR: cpustate->FSR = ((info->i & cpustate->picRAMmask) | (UINT8)(~cpustate->picRAMmask)); break;
+ }
+}
+
+
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+static CPU_GET_INFO( pic16c62x )
+{
+ pic16c62x_state *cpustate = (device != NULL && device->token != NULL) ? get_safe_token(device) : NULL;
+
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(pic16c62x_state); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 1; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case DEVINFO_INT_ENDIANNESS: info->i = ENDIANNESS_LITTLE; break;
+ case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 4; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 2; break;
+
+ case CPUINFO_INT_DATABUS_WIDTH_PROGRAM: info->i = 16; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH_PROGRAM: info->i = 12; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT_PROGRAM: info->i = -1; break;
+ case CPUINFO_INT_DATABUS_WIDTH_DATA: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH_DATA: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT_DATA: info->i = 0; break;
+ case CPUINFO_INT_DATABUS_WIDTH_IO: info->i = 8; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH_IO: info->i = 5; break;
+ case CPUINFO_INT_ADDRBUS_SHIFT_IO: info->i = 0; break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = cpustate->PREVPC; break;
+
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + PIC16C62x_PC: info->i = cpustate->PC; break;
+ /* This is actually not a stack pointer, but the stack contents */
+ case CPUINFO_INT_SP:
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK7: info->i = cpustate->STACK[7]; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK6: info->i = cpustate->STACK[6]; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK5: info->i = cpustate->STACK[5]; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK4: info->i = cpustate->STACK[4]; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK3: info->i = cpustate->STACK[3]; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK2: info->i = cpustate->STACK[2]; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK1: info->i = cpustate->STACK[1]; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_STK0: info->i = cpustate->STACK[0]; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_W: info->i = cpustate->W; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_ALU: info->i = cpustate->ALU; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_STR: info->i = cpustate->STATUS; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_OPT: info->i = cpustate->OPTION; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_TMR0: info->i = cpustate->TMR0; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_WDT: info->i = cpustate->WDT; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_PSCL: info->i = cpustate->prescaler; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_PRTA: info->i = cpustate->PORTA; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_PRTB: info->i = cpustate->PORTB; break;
+ case CPUINFO_INT_REGISTER + PIC16C62x_FSR: info->i = ((cpustate->FSR & cpustate->picRAMmask) | (UINT8)(~cpustate->picRAMmask)); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(pic16c62x); break;
+ case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(pic16c62x); break;
+ case CPUINFO_FCT_RESET: /* set per-CPU */ break;
+ case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(pic16c62x); break;
+ case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(pic16c62x); break;
+ case CPUINFO_FCT_BURN: info->burn = NULL; break;
+ case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(pic16c62x); break;
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cpustate->icount; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "PIC16C62x"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Microchip"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Tony La Porta"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%01x%c%c%c%c%c %c%c%c%03x",
+ (cpustate->STATUS & 0xe0) >> 5, /* Register bank */
+ cpustate->STATUS & 0x10 ? '.':'O', /* WDT Overflow */
+ cpustate->STATUS & 0x08 ? 'P':'D', /* Power/Down */
+ cpustate->STATUS & 0x04 ? 'Z':'.', /* Zero */
+ cpustate->STATUS & 0x02 ? 'c':'b', /* Nibble Carry/Borrow */
+ cpustate->STATUS & 0x01 ? 'C':'B', /* Carry/Borrow */
+
+ cpustate->OPTION & 0x20 ? 'C':'T', /* Counter/Timer */
+ cpustate->OPTION & 0x10 ? 'N':'P', /* Negative/Positive */
+ cpustate->OPTION & 0x08 ? 'W':'T', /* WatchDog/Timer */
+ cpustate->OPTION & 0x08 ? (1<<(cpustate->OPTION&7)) : (2<<(cpustate->OPTION&7)) );
+ break;
+
+ case CPUINFO_STR_REGISTER + PIC16C62x_PC: sprintf(info->s, "PC:%03X", cpustate->PC); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_W: sprintf(info->s, "W:%02X", cpustate->W); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_ALU: sprintf(info->s, "ALU:%02X", cpustate->ALU); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_STR: sprintf(info->s, "STR:%02X", cpustate->STATUS); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_TMR0: sprintf(info->s, "TMR:%02X", cpustate->TMR0); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_WDT: sprintf(info->s, "WDT:%04X", cpustate->WDT); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_OPT: sprintf(info->s, "OPT:%02X", cpustate->OPTION); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_STK0: sprintf(info->s, "STK0:%03X", cpustate->STACK[0]); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_STK1: sprintf(info->s, "STK1:%03X", cpustate->STACK[1]); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_STK2: sprintf(info->s, "STK2:%03X", cpustate->STACK[2]); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_STK3: sprintf(info->s, "STK3:%03X", cpustate->STACK[3]); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_STK4: sprintf(info->s, "STK4:%03X", cpustate->STACK[4]); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_STK5: sprintf(info->s, "STK5:%03X", cpustate->STACK[5]); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_STK6: sprintf(info->s, "STK6:%03X", cpustate->STACK[6]); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_STK7: sprintf(info->s, "STK7:%03X", cpustate->STACK[7]); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_PRTA: sprintf(info->s, "PRTA:%01X", ((cpustate->PORTA) & 0x1f)); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_PRTB: sprintf(info->s, "PRTB:%02X", cpustate->PORTB); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_TRSA: sprintf(info->s, "TRSA:%01X", ((cpustate->TRISA) & 0x1f)); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_TRSB: sprintf(info->s, "TRSB:%02X", cpustate->TRISB); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_FSR: sprintf(info->s, "FSR:%02X", ((cpustate->FSR) & cpustate->picRAMmask) | (UINT8)(~cpustate->picRAMmask)); break;
+ case CPUINFO_STR_REGISTER + PIC16C62x_PSCL: sprintf(info->s, "PSCL:%c%02X", ((cpustate->OPTION & 0x08) ? 'W':'T'), cpustate->prescaler); break;
+ }
+}
+
+
+/****************************************************************************
+ * PIC16C620
+ ****************************************************************************/
+/****************************************************************************
+ * Internal Memory Map
+ ****************************************************************************/
+
+static ADDRESS_MAP_START( pic16c620_rom, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0x000, 0x1ff) AM_ROM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( pic16c620_ram, ADDRESS_SPACE_DATA, 8 )
+ AM_RANGE(0x00, 0x06) AM_RAM
+ AM_RANGE(0x0a, 0x0c) AM_RAM
+ AM_RANGE(0x1f, 0x6f) AM_RAM
+ AM_RANGE(0x80, 0x86) AM_RAM
+ AM_RANGE(0x8a, 0x8e) AM_RAM
+ AM_RANGE(0x9f, 0x9f) AM_RAM
+ADDRESS_MAP_END
+
+
+/****************************************************************************
+ * PIC16C620 Reset
+ ****************************************************************************/
+
+static CPU_RESET( pic16c620 )
+{
+ pic16c62x_state *cpustate = get_safe_token(device);
+
+ update_internalram_ptr(cpustate);
+
+ cpustate->picmodel = 0x16C620;
+ cpustate->picRAMmask = 0xff;
+ cpustate->reset_vector = 0x0;
+ pic16c62x_reset_regs(cpustate);
+ SET(cpustate->STATUS, (TO_FLAG | PD_FLAG));
+}
+
+
+/**************************************************************************
+ * CPU-specific get_info
+ **************************************************************************/
+
+CPU_GET_INFO( pic16c620 )
+{
+ switch (state)
+ {
+ case CPUINFO_INT_ADDRBUS_WIDTH_PROGRAM: info->i = 9; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH_DATA: info->i = 8; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(pic16c620); break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP_PROGRAM: info->internal_map16 = ADDRESS_MAP_NAME(pic16c620_rom); break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP_DATA: info->internal_map8 = ADDRESS_MAP_NAME(pic16c620_ram); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "PIC16C620"); break;
+
+ default: CPU_GET_INFO_CALL(pic16c62x); break;
+ }
+}
+
+
+/****************************************************************************
+ * PIC16C621
+ ****************************************************************************/
+/****************************************************************************
+ * Internal Memory Map
+ ****************************************************************************/
+
+static ADDRESS_MAP_START( pic16c621_rom, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0x000, 0x3ff) AM_ROM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( pic16c621_ram, ADDRESS_SPACE_DATA, 8 )
+ AM_RANGE(0x00, 0x06) AM_RAM
+ AM_RANGE(0x0a, 0x0c) AM_RAM
+ AM_RANGE(0x1f, 0x6f) AM_RAM
+ AM_RANGE(0x80, 0x86) AM_RAM
+ AM_RANGE(0x8a, 0x8e) AM_RAM
+ AM_RANGE(0x9f, 0x9f) AM_RAM
+ADDRESS_MAP_END
+
+
+/****************************************************************************
+ * PIC16C621 Reset
+ ****************************************************************************/
+
+static CPU_RESET( pic16c621 )
+{
+ pic16c62x_state *cpustate = get_safe_token(device);
+
+ update_internalram_ptr(cpustate);
+
+ cpustate->picmodel = 0x16C621;
+ cpustate->picRAMmask = 0xff;
+ cpustate->reset_vector = 0x0;
+ pic16c62x_reset_regs(cpustate);
+ SET(cpustate->STATUS, (TO_FLAG | PD_FLAG));
+}
+
+
+/**************************************************************************
+ * CPU-specific get_info
+ **************************************************************************/
+
+CPU_GET_INFO( pic16c621 )
+{
+ switch (state)
+ {
+ case CPUINFO_INT_ADDRBUS_WIDTH_PROGRAM: info->i = 10; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH_DATA: info->i = 8; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(pic16c621); break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP_PROGRAM: info->internal_map16 = ADDRESS_MAP_NAME(pic16c621_rom); break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP_DATA: info->internal_map8 = ADDRESS_MAP_NAME(pic16c621_ram); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "PIC16C621"); break;
+
+ default: CPU_GET_INFO_CALL(pic16c62x); break;
+ }
+}
+
+
+/****************************************************************************
+ * PIC16C622
+ ****************************************************************************/
+/****************************************************************************
+ * Internal Memory Map
+ ****************************************************************************/
+
+static ADDRESS_MAP_START( pic16c622_rom, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0x000, 0x7ff) AM_ROM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( pic16c622_ram, ADDRESS_SPACE_DATA, 8 )
+ AM_RANGE(0x00, 0x06) AM_RAM
+ AM_RANGE(0x0a, 0x0c) AM_RAM
+ AM_RANGE(0x1f, 0x7f) AM_RAM
+ AM_RANGE(0x80, 0x86) AM_RAM
+ AM_RANGE(0x8a, 0x8e) AM_RAM
+ AM_RANGE(0x9f, 0xbf) AM_RAM
+ADDRESS_MAP_END
+
+
+/****************************************************************************
+ * PIC16C622 Reset
+ ****************************************************************************/
+
+static CPU_RESET( pic16c622 )
+{
+ pic16c62x_state *cpustate = get_safe_token(device);
+
+ update_internalram_ptr(cpustate);
+
+ cpustate->picmodel = 0x16C622;
+ cpustate->picRAMmask = 0xff;
+ cpustate->reset_vector = 0x0;
+ pic16c62x_reset_regs(cpustate);
+ SET(cpustate->STATUS, (TO_FLAG | PD_FLAG));
+}
+
+
+/**************************************************************************
+ * CPU-specific get_info
+ **************************************************************************/
+
+CPU_GET_INFO( pic16c622 )
+{
+ switch (state)
+ {
+ case CPUINFO_INT_ADDRBUS_WIDTH_PROGRAM: info->i = 11; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH_DATA: info->i = 8; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(pic16c622); break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP_PROGRAM: info->internal_map16 = ADDRESS_MAP_NAME(pic16c622_rom); break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP_DATA: info->internal_map8 = ADDRESS_MAP_NAME(pic16c622_ram); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "PIC16C622"); break;
+
+ default: CPU_GET_INFO_CALL(pic16c62x); break;
+ }
+}
+
+
+/****************************************************************************
+ * PIC16C620A
+ ****************************************************************************/
+/****************************************************************************
+ * Internal Memory Map
+ ****************************************************************************/
+
+static ADDRESS_MAP_START( pic16c620a_rom, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0x000, 0x1ff) AM_ROM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( pic16c620a_ram, ADDRESS_SPACE_DATA, 8 )
+ AM_RANGE(0x00, 0x06) AM_RAM
+ AM_RANGE(0x0a, 0x0c) AM_RAM
+ AM_RANGE(0x1f, 0x6f) AM_RAM
+ AM_RANGE(0x70, 0x7f) AM_RAM AM_SHARE(0)
+ AM_RANGE(0x80, 0x86) AM_RAM
+ AM_RANGE(0x8a, 0x8e) AM_RAM
+ AM_RANGE(0x9f, 0x9f) AM_RAM
+ AM_RANGE(0xf0, 0xff) AM_RAM AM_SHARE(0)
+ADDRESS_MAP_END
+
+
+/****************************************************************************
+ * PIC16C620A Reset
+ ****************************************************************************/
+
+static CPU_RESET( pic16c620a )
+{
+ pic16c62x_state *cpustate = get_safe_token(device);
+
+ update_internalram_ptr(cpustate);
+
+ cpustate->picmodel = 0x16C620A;
+ cpustate->picRAMmask = 0xff;
+ cpustate->reset_vector = 0x0;
+ pic16c62x_reset_regs(cpustate);
+ SET(cpustate->STATUS, (TO_FLAG | PD_FLAG));
+}
+
+
+/**************************************************************************
+ * CPU-specific get_info
+ **************************************************************************/
+
+CPU_GET_INFO( pic16c620a )
+{
+ switch (state)
+ {
+ case CPUINFO_INT_ADDRBUS_WIDTH_PROGRAM: info->i = 9; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH_DATA: info->i = 8; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(pic16c620a); break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP_PROGRAM: info->internal_map16 = ADDRESS_MAP_NAME(pic16c620a_rom); break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP_DATA: info->internal_map8 = ADDRESS_MAP_NAME(pic16c620a_ram); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "PIC16C620A"); break;
+
+ default: CPU_GET_INFO_CALL(pic16c62x); break;
+ }
+}
+
+
+/****************************************************************************
+ * PIC16C621A
+ ****************************************************************************/
+/****************************************************************************
+ * Internal Memory Map
+ ****************************************************************************/
+
+static ADDRESS_MAP_START( pic16c621a_rom, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0x000, 0x3ff) AM_ROM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( pic16c621a_ram, ADDRESS_SPACE_DATA, 8 )
+ AM_RANGE(0x00, 0x06) AM_RAM
+ AM_RANGE(0x0a, 0x0c) AM_RAM
+ AM_RANGE(0x1f, 0x6f) AM_RAM
+ AM_RANGE(0x70, 0x7f) AM_RAM AM_SHARE(0)
+ AM_RANGE(0x80, 0x86) AM_RAM
+ AM_RANGE(0x8a, 0x8e) AM_RAM
+ AM_RANGE(0x9f, 0x9f) AM_RAM
+ AM_RANGE(0xf0, 0xff) AM_RAM AM_SHARE(0)
+ADDRESS_MAP_END
+
+
+/****************************************************************************
+ * PIC16C621A Reset
+ ****************************************************************************/
+
+static CPU_RESET( pic16c621a )
+{
+ pic16c62x_state *cpustate = get_safe_token(device);
+
+ update_internalram_ptr(cpustate);
+
+ cpustate->picmodel = 0x16C621A;
+ cpustate->picRAMmask = 0xff;
+ cpustate->reset_vector = 0x0;
+ pic16c62x_reset_regs(cpustate);
+ SET(cpustate->STATUS, (TO_FLAG | PD_FLAG));
+}
+
+
+/**************************************************************************
+ * CPU-specific get_info
+ **************************************************************************/
+
+CPU_GET_INFO( pic16c621a )
+{
+ switch (state)
+ {
+ case CPUINFO_INT_ADDRBUS_WIDTH_PROGRAM: info->i = 10; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH_DATA: info->i = 8; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(pic16c621a); break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP_PROGRAM: info->internal_map16 = ADDRESS_MAP_NAME(pic16c621a_rom); break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP_DATA: info->internal_map8 = ADDRESS_MAP_NAME(pic16c621a_ram); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "PIC16C621A"); break;
+
+ default: CPU_GET_INFO_CALL(pic16c62x); break;
+ }
+}
+
+
+/****************************************************************************
+ * PIC16C622A
+ ****************************************************************************/
+/****************************************************************************
+ * Internal Memory Map
+ ****************************************************************************/
+
+static ADDRESS_MAP_START( pic16c622a_rom, ADDRESS_SPACE_PROGRAM, 16 )
+ AM_RANGE(0x000, 0x7ff) AM_ROM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( pic16c622a_ram, ADDRESS_SPACE_DATA, 8 )
+ AM_RANGE(0x00, 0x06) AM_RAM
+ AM_RANGE(0x0a, 0x0c) AM_RAM
+ AM_RANGE(0x1f, 0x6f) AM_RAM
+ AM_RANGE(0x70, 0x7f) AM_RAM AM_SHARE(0)
+ AM_RANGE(0x80, 0x86) AM_RAM
+ AM_RANGE(0x8a, 0x8e) AM_RAM
+ AM_RANGE(0x9f, 0xbf) AM_RAM
+ AM_RANGE(0xf0, 0xff) AM_RAM AM_SHARE(0)
+ADDRESS_MAP_END
+
+
+/****************************************************************************
+ * PIC16C622A Reset
+ ****************************************************************************/
+
+static CPU_RESET( pic16c622a )
+{
+ pic16c62x_state *cpustate = get_safe_token(device);
+
+ update_internalram_ptr(cpustate);
+
+ cpustate->picmodel = 0x16C622A;
+ cpustate->picRAMmask = 0xff;
+ cpustate->reset_vector = 0x0;
+ pic16c62x_reset_regs(cpustate);
+ SET(cpustate->STATUS, (TO_FLAG | PD_FLAG));
+}
+
+
+/**************************************************************************
+ * CPU-specific get_info
+ **************************************************************************/
+
+CPU_GET_INFO( pic16c622a )
+{
+ switch (state)
+ {
+ case CPUINFO_INT_ADDRBUS_WIDTH_PROGRAM: info->i = 11; break;
+ case CPUINFO_INT_ADDRBUS_WIDTH_DATA: info->i = 8; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(pic16c622a); break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP_PROGRAM: info->internal_map16 = ADDRESS_MAP_NAME(pic16c622a_rom); break;
+ case CPUINFO_PTR_INTERNAL_MEMORY_MAP_DATA: info->internal_map8 = ADDRESS_MAP_NAME(pic16c622a_ram); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "PIC16C622A"); break;
+
+ default: CPU_GET_INFO_CALL(pic16c62x); break;
+ }
+}
+
diff --git a/src/emu/cpu/pic16c62x/pic16c62x.h b/src/emu/cpu/pic16c62x/pic16c62x.h
new file mode 100644
index 00000000000..712ff9c1452
--- /dev/null
+++ b/src/emu/cpu/pic16c62x/pic16c62x.h
@@ -0,0 +1,84 @@
+ /**************************************************************************\
+ * Microchip PIC16C62X Emulator *
+ * *
+ * Based On *
+ * Microchip PIC16C5X Emulator *
+ * Copyright Tony La Porta *
+ * Originally written for the MAME project. *
+ * *
+ * *
+ * Addressing architecture is based on the Harvard addressing scheme. *
+ * *
+ \**************************************************************************/
+
+#pragma once
+
+#ifndef __PIC16C62X_H__
+#define __PIC16C62X_H__
+
+
+#include "cpuintrf.h"
+
+
+/**************************************************************************
+ * Internal Clock divisor
+ *
+ * External Clock is divided internally by 4 for the instruction cycle
+ * times. (Each instruction cycle passes through 4 machine states). This
+ * is handled by the cpu execution engine.
+ */
+
+enum
+{
+ PIC16C62x_PC=1, PIC16C62x_STK0, PIC16C62x_STK1, PIC16C62x_STK2,
+ PIC16C62x_STK3, PIC16C62x_STK4, PIC16C62x_STK5, PIC16C62x_STK6,
+ PIC16C62x_STK7, PIC16C62x_FSR, PIC16C62x_W, PIC16C62x_ALU,
+ PIC16C62x_STR, PIC16C62x_OPT, PIC16C62x_TMR0, PIC16C62x_PRTA,
+ PIC16C62x_PRTB, PIC16C62x_WDT, PIC16C62x_TRSA, PIC16C62x_TRSB,
+ PIC16C62x_PSCL
+};
+
+#define PIC16C62x_T0 0
+
+
+/****************************************************************************
+ * Function to configure the CONFIG register. This is actually hard-wired
+ * during ROM programming, so should be called in the driver INIT, with
+ * the value if known (available in HEX dumps of the ROM).
+ */
+
+void pic16c62x_set_config(const device_config *cpu, int data);
+
+
+
+CPU_GET_INFO( pic16c620 );
+#define CPU_PIC16C620 CPU_GET_INFO_NAME( pic16c620 )
+
+
+CPU_GET_INFO( pic16c620a );
+#define CPU_PIC16C620A CPU_GET_INFO_NAME( pic16c620a )
+
+
+//CPU_GET_INFO( pic16cr620a );
+//#define CPU_PIC16CR620A CPU_GET_INFO_NAME( pic16cr620a )
+
+
+CPU_GET_INFO( pic16c621 );
+#define CPU_PIC16C621 CPU_GET_INFO_NAME( pic16c621 )
+
+
+CPU_GET_INFO( pic16c621a );
+#define CPU_PIC16C621A CPU_GET_INFO_NAME( pic16c621a )
+
+CPU_GET_INFO( pic16c622 );
+#define CPU_PIC16C622 CPU_GET_INFO_NAME( pic16c622 )
+
+
+CPU_GET_INFO( pic16c622a );
+#define CPU_PIC16C622A CPU_GET_INFO_NAME( pic16c622a )
+
+
+CPU_DISASSEMBLE( pic16c62x );
+
+
+#endif /* __PIC16C62X_H__ */
diff --git a/src/mame/mame.mak b/src/mame/mame.mak
index 25ef729539f..e04a055c48b 100644
--- a/src/mame/mame.mak
+++ b/src/mame/mame.mak
@@ -76,6 +76,7 @@ CPUS += SH2
CPUS += SH4
CPUS += DSP32C
CPUS += PIC16C5X
+CPUS += PIC16C62X
CPUS += G65816
CPUS += SPC700
CPUS += E1
diff --git a/src/tools/unidasm.c b/src/tools/unidasm.c
index 63b9a7a67b0..a0ec77d78e1 100644
--- a/src/tools/unidasm.c
+++ b/src/tools/unidasm.c
@@ -166,6 +166,7 @@ CPU_DISASSEMBLE( pdp1 );
CPU_DISASSEMBLE( tx0_64kw );
CPU_DISASSEMBLE( tx0_8kw );
CPU_DISASSEMBLE( pic16c5x );
+CPU_DISASSEMBLE( pic16c62x );
CPU_DISASSEMBLE( powerpc );
CPU_DISASSEMBLE( rsp );
CPU_DISASSEMBLE( s2650 );
@@ -291,6 +292,7 @@ static const dasm_table_entry dasm_table[] =
{ "tx0_64kw", _32be, -2, CPU_DISASSEMBLE_NAME(tx0_64kw) },
{ "tx0_8kw", _32be, -2, CPU_DISASSEMBLE_NAME(tx0_8kw) },
{ "pic16c5x", _16le, -1, CPU_DISASSEMBLE_NAME(pic16c5x) },
+ { "pic16c62x", _16le, -1, CPU_DISASSEMBLE_NAME(pic16c62x) },
{ "powerpc", _32be, 0, CPU_DISASSEMBLE_NAME(powerpc) },
{ "rsp", _32le, 0, CPU_DISASSEMBLE_NAME(rsp) },
{ "s2650", _8bit, 0, CPU_DISASSEMBLE_NAME(s2650) },