diff options
Diffstat (limited to 'src/emu')
| -rw-r--r-- | src/emu/cpu/cpu.mak | 15 | ||||
| -rw-r--r-- | src/emu/cpu/pic16c62x/16c62xdsm.c | 269 | ||||
| -rw-r--r-- | src/emu/cpu/pic16c62x/dis16c62x.c | 136 | ||||
| -rw-r--r-- | src/emu/cpu/pic16c62x/pic16c62x.c | 1607 | ||||
| -rw-r--r-- | src/emu/cpu/pic16c62x/pic16c62x.h | 84 |
5 files changed, 2111 insertions, 0 deletions
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__ */ |
