text:  /**************************************************************************\
   *                      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.                                          *
   *                                                                          *
   \**************************************************************************/
  
  #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
  
  static const char *const regfile[32] = { "Reg$00 (IND)",    "Reg$01 (TMR)",    "Reg$02 (PCL)",  "Reg$03 (ST)", "Reg$04 (FSR)", "Reg$05 (PTA)", "Reg$06 (PTB)", "Reg$07 (PTC)",
  								 "Reg$08", "Reg$09", "Reg$0A", "Reg$0B", "Reg$0C", "Reg$0D", "Reg$0E", "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" };
  
  static const char *const dest[2] = { "W", "Reg" };
  
  static const char *const PIC16C5xFormats[] = {
  	FMT("000000000000", "nop"),
  	FMT("000000000010", "option"),
  	FMT("000000000011", "sleep"),
  	FMT("000000000100", "clrwdt"),
  	FMT("000000000101", "tris   Port A"),
  	FMT("000000000110", "tris   Port B"),
  	FMT("000000000111", "tris   Port C"),
  	FMT("0000001fffff", "movwf  %F"),
  	FMT("000001000000", "clrw"),
  	FMT("0000011fffff", "clrf   %F"),
  	FMT("000010dfffff", "subwf  %F,%D"),
  	FMT("000011dfffff", "decf   %F,%D"),
  	FMT("000100dfffff", "iorwf  %F,%D"),
  	FMT("000101dfffff", "andwf  %F,%D"),
  	FMT("000110dfffff", "xorwf  %F,%D"),
  	FMT("000111dfffff", "addwf  %F,%D"),
  	FMT("001000dfffff", "movf   %F,%D"),
  	FMT("001001dfffff", "comf   %F,%D"),
  	FMT("001010dfffff", "incf   %F,%D"),
  	FMT("001011dfffff", "decfsz %F,%D"),
  	FMT("001100dfffff", "rrf    %F,%D"),
  	FMT("001101dfffff", "rlf    %F,%D"),
  	FMT("001110dfffff", "swapf  %F,%D"),
  	FMT("001111dfffff", "incfsz %F,%D"),
  	FMT("0100bbbfffff", "bcf    %F,%B"),
  	FMT("0101bbbfffff", "bsf    %F,%B"),
  	FMT("0110bbbfffff", "btfsc  %F,%B"),
  	FMT("0111bbbfffff", "btfss  %F,%B"),
  	FMT("1000kkkkkkkk", "retlw  %K"),
  	FMT("1001aaaaaaaa", "call   %A"),
  	FMT("101aaaaaaaaa", "goto   %A"),
  	FMT("1100kkkkkkkk", "movlw  %K"),
  	FMT("1101kkkkkkkk", "iorlw  %K"),
  	FMT("1110kkkkkkkk", "andlw  %K"),
  	FMT("1111kkkkkkkk", "xorlw  %K"),
  	NULL
  };
  
  #define MAX_OPS (((sizeof(PIC16C5xFormats) / sizeof(PIC16C5xFormats[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 */
  } PIC16C5xOpcode;
  
  static PIC16C5xOpcode 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 = PIC16C5xFormats; i = 0;
  	while (*ops)
  	{
  		p = *ops;
  		mask = 0; bits = 0; bit = 11;
  		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':
  					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( pic16c5x )
  {
  	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 = 27;
  		code <<= 16;
  		code |= READARG16(2*(pc+cnt));
  		cnt++;
  	}
  	else
  	{
  		bit = 11;
  	}
  
  	/* 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':  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': sprintf(num,"%s",regfile[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;
  }
  