/* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

#include "generator.h"

#define BUFLEN 1024
#define FNAME_CPUDEF "def68k.def"
#define FNAME_OUTIIBS "def68k-iibs.h"
#define FNAME_OUTFUNCS "def68k-funcs.h"
#define FNAME_OUTPROTO "def68k-proto.h"

typedef enum {
  bit0, bit1, bitz, bite, bitE, bitf, bitF, biti, bitn, bitN, bitc, bitv
} t_bit;

/* file-scope global variables */

static int total = 0;
static int clocks_movetable[]; /* pre-declaration */

/* private functions for forward references */

void procline(char *line, int lineno, FILE *outiibs, FILE *outfuncs,
	      FILE *outproto);
int clocks_ea(t_datatype type);
int clocks_eacalc(t_datatype type, t_size size);
int clocks_6or8(t_datatype type);
int clocks_typetoindex(t_datatype type);

/* program entry routine */

int main(int argc, char *argv[])
{
  FILE *input, *outiibs, *outfuncs, *outproto;
  char buf[BUFLEN], *p;
  int lineno = 0;

  (void)argc;
  (void)argv;

  /* open output files and write headers */

  if ((outiibs = fopen(FNAME_OUTIIBS, "w")) == NULL) {
    perror("fopen outiibs");
    exit(1);
  }
  fprintf(outiibs, "/* automatically generated by def68k.c */\n\n");
  fprintf(outiibs, "t_iib iibs[] = {\n");
  fprintf(outiibs, "  /* mask, bits, mnemonic, { priv, endblk, zero, ");
  fprintf(outiibs, "used, set },\n");
  fprintf(outiibs, "     size, stype, dtype, sbitpos, dbitpos, immvalue, ");
  fprintf(outiibs, "cc, funcnum */\n");

  if ((outfuncs = fopen(FNAME_OUTFUNCS, "w")) == NULL) {
    perror("fopen outfuncs");
    exit(1);
  }
  fprintf(outfuncs, "/* automatically generated by def68k.c */\n\n");
  fprintf(outfuncs, "void (*cpu68k_funcindex[])(t_ipc *ipc) = {\n");
  fprintf(outfuncs, "  /* function */\n");

  if ((outproto = fopen(FNAME_OUTPROTO, "w")) == NULL) {
    perror("fopen outproto");
    exit(1);
  }
  fprintf(outproto, "/* automatically generated by def68k.c */\n\n");

  /* open input file */

  if ((input = fopen(FNAME_CPUDEF, "r")) == NULL) {
    perror("fopen input");
    exit(1);
  }

  /* loop until end of file */

  printf("Writing CPU definitions... ");
  fflush(stdout);

  while (!feof(input)) {
    /* use unix line numbering from 1 */
    lineno++;
    /* read a line */
    if (ferror(input)) {
      break;
    }
    if (fgets(buf, BUFLEN, input) == NULL) {
      break;
      /* huh? why does this cause fgets to say 'Unknown error'?! */
      perror("fgets");
      exit(1);
    }
    /* remove newline */
    buf[strlen(buf)-1] = '\0';
    /* remove comment */
    if ((p = strchr(buf, ';')) != NULL) {
      *p = '\0';
    }
    /* remove leading spaces */
    p = buf;
    while (*p == ' ')
      p++;
    /* blank line? */
    if (!*p)
      continue;
    /* process line */
    procline(buf, lineno, outiibs, outfuncs, outproto);
  }

  /* close input */

  if (fclose(input)) {
    perror("fclose input");
    exit(1);
  }

  /* output footer */

  fprintf(outiibs, "  { 0, 0, 0, { 0, 0, 0, 0, 0 }, "
	  "0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }\n");
  fprintf(outiibs, "};\n");
  fprintf(outiibs, "int iibs_num = %d;\n", total);

  fprintf(outfuncs, "};\n");

  /* close outputs */

  if (fclose(outiibs)) {
    perror("fclose outiibs");
    exit(1);
  }
  if (fclose(outfuncs)) {
    perror("fclose outfuncs");
    exit(1);
  }
  if (fclose(outproto)) {
    perror("fclose outproto");
    exit(1);
  }

  printf("done.\n");
  fflush(stdout);

  return(0);
}  

/* process a line */

void procline(char *line, int lineno, FILE *outiibs, FILE *outfuncs,
	      FILE *outproto) {
  int i;
  char *p;
  t_bit bit = bit0, lastbit = bit0;
  int start[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
  int num[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
  char mnemonic[16], *m;
  int setting;
  int clocks;

  /* parameters to fill in about instruction */
  int mnemonic_num;
  uint16 mask = 0, bits = 0;        /* see struct t_iib for details on */
  int priv = 0, endblk = 0;         /* these variables */
  int imm_notzero = 0;
  int used = 0, set = 0;
  t_size isize = sz_none;
  int expand_s_immsize = 0, expand_s_ea_e = 0;
  int expand_d_ea_e = 0, expand_d_ea_f = 0;
  t_datatype dtype = dt_Ill;
  t_datatype stype = dt_Ill;
  int e[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
  int f[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
  int immvalue = 0;
  int sbitpos = 0, dbitpos = 0;

  p = line;

  /* bitpattern */

  for (i = 15; i >= 0; i--) {
    while (*p == ' ')
      p++;

    switch(*p) {
    case '0': bit = bit0; mask |= 1<<i; break;
    case '1': bit = bit1; mask |= 1<<i; bits |= 1<<i; break;
    case 'z': bit = bitz; break;
    case 'e': bit = bite; break;
    case 'E': bit = bitE; break;
    case 'f': bit = bitf; break;
    case 'F': bit = bitF; break;
    case 'n': bit = bitn; break;
    case 'N': bit = bitN; break;
    case 'i': bit = biti; break;
    case 'c': bit = bitc; break;
    case 'V': bit = bitv; break;
    default:
      fprintf(stderr, "%d: unknown char %c in bitpattern\n", lineno, *p);
      exit(1);
    }

    if (*p != '0' && *p != '1') {
      if (num[bit]) {
	/* we've seen this bit before, make sure the last bit was the same */
	if (bit < 15 && bit != lastbit) {
	  fprintf(stderr, "%d: Non contiguous bits of %c\n", lineno, *p);
	  exit(1);
	}
      }
      /* we're looping down, so the last time start[bit] is set is the start */
      start[bit] = i;
      /* record how many of these bits there are */
      num[bit]++;
    }
    p++;
    lastbit = bit;
  }
  /* skip spaces and skip tab to get to next field */
  while (*p == ' ')
    p++;
  if (*p++ != '\t') {
    fprintf(stderr, "%d: Tab not found at end of bitpattern\n", lineno);
    exit(1);
  }

  /* misc flags */

  if (*p == '0') {
    priv = 0;
  } else if (*p == '1') {
    priv = 1;
  } else {
    fprintf(stderr, "%d: Priv flag not 0 or 1\n", lineno);
    exit(1);
  }
  p++;
  /* skip spaces to next field */
  while (*p == ' ')
    p++;
  if (*p == '0') {
    endblk = 0;
  } else if (*p == '1') {
    endblk = 1;
  } else {
    fprintf(stderr, "%d: End-block flag not 0 or 1\n", lineno);
    exit(1);
  }
  p++;
  /* skip spaces and skip tab to get to next field */
  while (*p == ' ')
    p++;
  if (*p++ != '\t') {
    fprintf(stderr, "%d: Tab not found at end of flags\n", lineno);
    exit(1);
  }

  /* used flags */

  for (i = 0; i < 5; i++) {
    while (*p == ' ')
      p++;
    switch(*p++) {
    case '-': break;
    case 'x': break;
    case 'X': used |= 1<<i; break;
    case 'N': used |= 1<<i; break;
    case 'Z': used |= 1<<i; break;
    case 'V': used |= 1<<i; break;
    case 'C': used |= 1<<i; break;
    case '0': used |= 1<<i; break;
    case '1': used |= 1<<i; break;
    default:
      fprintf(stderr, "%d: Did not understand used flag %d\n", lineno, i);
      exit(1);
    }
  }
  /* skip spaces and skip tab to get to next field */
  while (*p == ' ')
    p++;
  if (*p++ != '\t') {
    fprintf(stderr, "%d: Tab not found at end of used flags\n", lineno);
    exit(1);
  }

  /* set flags */

  for (i = 0; i < 5; i++) {
    while (*p == ' ')
      p++;
    switch(*p++) {
    case '-': break;
    case 'x': break;
    case 'X': set |= 1<<i; break;
    case 'N': set |= 1<<i; break;
    case 'Z': set |= 1<<i; break;
    case 'V': set |= 1<<i; break;
    case 'C': set |= 1<<i; break;
    case '0': set |= 1<<i; break;
    case '1': set |= 1<<i; break;
    default:
      fprintf(stderr, "%d: Did not understand set flag %d\n", lineno, i);
      exit(1);
    }
  }
  /* skip spaces and skip tab to get to next field */
  while (*p == ' ')
    p++;
  if (*p++ != '\t') {
    fprintf(stderr, "%d: Tab not found at end of set flags\n", lineno);
    exit(1);
  }
      
  /* mnemonic */

  m = mnemonic;
  while (*p && (*p != '.') && (*p != ' ') && (*p != '\t')) {
    *m++ = *p++;
  }
  if (*p == '\t') {
    fprintf(stderr, "%d: Incorrect number of fields - extra tab found\n",
	    lineno);
    exit(1);
  }
  *m = '\0';
  for (mnemonic_num = 0; *mnemonic_table[mnemonic_num].name; mnemonic_num++)
    if (!strcmp(mnemonic_table[mnemonic_num].name, mnemonic))
      break;
  if (!*mnemonic_table[mnemonic_num].name) {
    fprintf(stderr, "%d: Unknown mnemonic '%s'\n", lineno, mnemonic);
    exit(1);
  }
  /* set defaults for isize */
  isize = sz_none;
  if (*p == '.') {
    switch(*++p) {
    case 'B': isize = sz_byte; break;
    case 'W': isize = sz_word; break;
    case 'L': isize = sz_long; break;
    case 'z':
      if (!num[bitz]) {
	fprintf(stderr, "%d: 'z' given as size but no 'z' in bit pattern\n",
		lineno);
	exit(1);
      }
      /* size will be set automatically later */
      break;
    default:
      fprintf(stderr, "%d: Unknown size '%c' after mnemonic\n",
	      lineno, *p);
      exit(1);
    }
    p++;
  } else {
    /* instruction is not sized */
    if (num[bitz]) {
      /* oh, perhaps it is but it's a mistake */
      fprintf(stderr, "%d: 'z's in bit pattern but no .z after mnemonic\n",
	      lineno);
      exit(1);
    }
  }
  while (*p == ' ')
    p++;
  if (*p == '\0') {
    /* no source and destination information given */
    if (num[bite] || num[bitE] || num[bitf] || num[bitF] ||
	num[biti] || num[bitn] || num[bitN] || num[bitv]) {
      fprintf(stderr, "%d: No information given after mnemonic\n", lineno);
      exit(1);
    }
  } else {
    switch(*p++) {
    case 'n':
    case 'N':
      if (*(p-1) == 'n') {
	sbitpos = start[bitn];
      } else {
	sbitpos = start[bitN];
      }
      if (*p++ != '(') {
	fprintf(stderr, "%d: missing qualifier for n()\n", lineno);
	exit(1);
      }
      if (!strncmp(p, "Dreg", 4)) { stype = dt_Dreg; p = p+4;
      } else if (!strncmp(p, "Areg", 4)) { stype = dt_Areg; p = p+4;
      } else if (!strncmp(p, "Aind", 4)) { stype = dt_Aind; p = p+4;
      } else if (!strncmp(p, "Ainc", 4)) { stype = dt_Ainc; p = p+4;
      } else if (!strncmp(p, "Adec", 4)) { stype = dt_Adec; p = p+4;
      } else if (!strncmp(p, "Adis", 4)) { stype = dt_Adis; p = p+4;
      } else if (!strncmp(p, "Aidx", 4)) { stype = dt_Aidx; p = p+4;
      } else if (!strncmp(p, "AbsW", 4)) { stype = dt_AbsW; p = p+4;
      } else if (!strncmp(p, "AbsL", 4)) { stype = dt_AbsL; p = p+4;
      } else if (!strncmp(p, "Pdis", 4)) { stype = dt_Pdis; p = p+4;
      } else if (!strncmp(p, "Pidx", 4)) { stype = dt_Pidx; p = p+4;
      } else {
	fprintf(stderr, "%d: unknown qualifier for n()\n", lineno);
	exit(1);
      }
      if (*p++ != ')') {
	fprintf(stderr, "%d: unknown qualifier for n()\n", lineno);
	exit(1);
      }
      break;
    case '#':
      switch(*p++) {
      case 'B': stype = dt_ImmB; break;
      case 'W': stype = dt_ImmW; break;
      case 'L': stype = dt_ImmL; break;
      case 'z': expand_s_immsize = 1; break;
      case 's':
	if (num[biti] != 8) {
	  fprintf(stderr, "%d: sign extend not from 8 bits\n", lineno);
	  exit(1);
	}
	stype = dt_Imm8s;
	break;
      case 'i':
	switch (num[biti]) {
	case 3: stype = dt_Imm3; break;
	case 4: stype = dt_Imm4; break;
	case 8: stype = dt_Imm8; break;
	default:
	  fprintf(stderr, "%d: unknown immediate data size or bad dimension\n",
		lineno);
	  exit(1);
	}
	sbitpos = start[biti]; 
	break;
      case 'I':
	imm_notzero = 1;
	switch (num[biti]) {
	case 3: stype = dt_Imm3; break;
	case 4: stype = dt_Imm4; break;
	case 8: stype = dt_Imm8; break;
	default:
	  fprintf(stderr, "%d: unknown immediate data size or bad dimension\n",
		lineno);
	  exit(1);
	}
	sbitpos = start[biti]; 
	break;
      case 'V':
	stype = dt_ImmV;
	sbitpos = start[bitv]; 
	break;
      default:
	p--;
	if (isdigit((int)*p)) {
	  immvalue = strtol(p, &p, 10);
	  stype = dt_ImmS;
	} else {
	  fprintf(stderr, "%d: unknown source immediate type #%c\n",
		  lineno, *(p-1));
	  exit(1);
	}
      }
      break;
    case 'e':
      expand_s_ea_e = 1;

      if (*p++ != '(') {
	fprintf(stderr, "%d: missing qualifier for EA\n", lineno);
	exit(1);
      }
      do {
	setting = 1;
	if (*p == '-') {
	  p++;
	  setting = 0;
	}
	if (!strncmp(p, "*", 1)) {
	  e[ea_Dreg] = e[ea_Areg] = e[ea_Aind] = e[ea_Ainc] = setting;
	  e[ea_Adec] = e[ea_Adis] = e[ea_Aidx] = e[ea_AbsW] = setting;
	  e[ea_AbsL] = e[ea_Pdis] = e[ea_Pidx] = e[ea_Imm] = setting;
	  p = p+1;
	} else if (!strncmp(p, "Regs", 4)) {
	  e[ea_Dreg] = e[ea_Areg] = setting;
	  p = p+4;
	} else if (!strncmp(p, "PC", 2)) {
	  e[ea_Pdis] = e[ea_Pidx] = setting;
	  p = p+2;
	} else if (!strncmp(p, "Amod", 4)) {
	  e[ea_Ainc] = e[ea_Adec] = setting;
	  p = p+4;
	} else if (!strncmp(p, "Dreg", 4)) { e[ea_Dreg] = setting; p = p+4;
	} else if (!strncmp(p, "Areg", 4)) { e[ea_Areg] = setting; p = p+4;
	} else if (!strncmp(p, "Aind", 4)) { e[ea_Aind] = setting; p = p+4;
	} else if (!strncmp(p, "Ainc", 4)) { e[ea_Ainc] = setting; p = p+4;
	} else if (!strncmp(p, "Adec", 4)) { e[ea_Adec] = setting; p = p+4;
	} else if (!strncmp(p, "Adis", 4)) { e[ea_Adis] = setting; p = p+4;
	} else if (!strncmp(p, "Aidx", 4)) { e[ea_Aidx] = setting; p = p+4;
	} else if (!strncmp(p, "AbsW", 4)) { e[ea_AbsW] = setting; p = p+4;
	} else if (!strncmp(p, "AbsL", 4)) { e[ea_AbsL] = setting; p = p+4;
	} else if (!strncmp(p, "Pdis", 4)) { e[ea_Pdis] = setting; p = p+4;
	} else if (!strncmp(p, "Pidx", 4)) { e[ea_Pidx] = setting; p = p+4;
	} else if (!strncmp(p, "Imm", 3))  { e[ea_Imm]  = setting; p = p+3;
	} else {
	  fprintf(stderr, "%d: unknown qualifier for EA\n", lineno);
	  exit(1);
	}
      } while (*p++ == ',');
      if (*(p-1) != ')') {
	fprintf(stderr, "%d: unknown qualifier for EA\n", lineno);
	exit(1);
      }
      break;
    default:
      fprintf(stderr, "%d: did not understand source operand\n", lineno);
      exit(1);
    }
    if (*p == ',') {
      /* there is a destination part */
      p++;
      switch(*p++) {
      case 'n':
      case 'N':
	if (*(p-1) == 'n') {
	  dbitpos = start[bitn];
	} else {
	  dbitpos = start[bitN];
	}
	if (*p++ != '(') {
	  fprintf(stderr, "%d: missing qualifier for n()\n", lineno);
	  exit(1);
	}
	if (!strncmp(p, "Dreg", 4)) { dtype = dt_Dreg; p = p+4;
	} else if (!strncmp(p, "Areg", 4)) { dtype = dt_Areg; p = p+4;
	} else if (!strncmp(p, "Aind", 4)) { dtype = dt_Aind; p = p+4;
	} else if (!strncmp(p, "Ainc", 4)) { dtype = dt_Ainc; p = p+4;
	} else if (!strncmp(p, "Adec", 4)) { dtype = dt_Adec; p = p+4;
	} else if (!strncmp(p, "Adis", 4)) { dtype = dt_Adis; p = p+4;
	} else if (!strncmp(p, "Aidx", 4)) { dtype = dt_Aidx; p = p+4;
	} else if (!strncmp(p, "AbsW", 4)) { dtype = dt_AbsW; p = p+4;
	} else if (!strncmp(p, "AbsL", 4)) { dtype = dt_AbsL; p = p+4;
	} else if (!strncmp(p, "Pdis", 4)) { dtype = dt_Pdis; p = p+4;
	} else if (!strncmp(p, "Pidx", 4)) { dtype = dt_Pidx; p = p+4;
	} else {
	  fprintf(stderr, "%d: unknown qualifier for n()\n", lineno);
	  exit(1);
	}
	if (*p++ != ')') {
	  fprintf(stderr, "%d: unknown qualifier for n()\n", lineno);
	  exit(1);
	}
	break;
      case 'e':
	expand_d_ea_e = 1;

	if (*p++ != '(') {
	  fprintf(stderr, "%d: missing qualifier for EA\n", lineno);
	  exit(1);
	}
	do {
	  setting = 1;
	  if (*p == '-') {
	    p++;
	    setting = 0;
	  }
	  if (!strncmp(p, "*", 1)) {
	    e[ea_Dreg] = e[ea_Areg] = e[ea_Aind] = e[ea_Ainc] = setting;
	    e[ea_Adec] = e[ea_Adis] = e[ea_Aidx] = e[ea_AbsW] = setting;
	    e[ea_AbsL] = e[ea_Pdis] = e[ea_Pidx] = e[ea_Imm] = setting;
	    p = p+1;
	  } else if (!strncmp(p, "Regs", 4)) {
	    e[ea_Dreg] = e[ea_Areg] = setting;
	    p = p+4;
	  } else if (!strncmp(p, "PC", 2)) {
	    e[ea_Pdis] = e[ea_Pidx] = setting;
	    p = p+2;
	  } else if (!strncmp(p, "Amod", 4)) {
	    e[ea_Ainc] = e[ea_Adec] = setting;
	    p = p+4;
	  } else if (!strncmp(p, "Dreg", 4)) { e[ea_Dreg] = setting; p = p+4;
	  } else if (!strncmp(p, "Areg", 4)) { e[ea_Areg] = setting; p = p+4;
	  } else if (!strncmp(p, "Aind", 4)) { e[ea_Aind] = setting; p = p+4;
	  } else if (!strncmp(p, "Ainc", 4)) { e[ea_Ainc] = setting; p = p+4;
	  } else if (!strncmp(p, "Adec", 4)) { e[ea_Adec] = setting; p = p+4;
	  } else if (!strncmp(p, "Adis", 4)) { e[ea_Adis] = setting; p = p+4;
	  } else if (!strncmp(p, "Aidx", 4)) { e[ea_Aidx] = setting; p = p+4;
	  } else if (!strncmp(p, "AbsW", 4)) { e[ea_AbsW] = setting; p = p+4;
	  } else if (!strncmp(p, "AbsL", 4)) { e[ea_AbsL] = setting; p = p+4;
	  } else if (!strncmp(p, "Pdis", 4)) { e[ea_Pdis] = setting; p = p+4;
	  } else if (!strncmp(p, "Pidx", 4)) { e[ea_Pidx] = setting; p = p+4;
	  } else if (!strncmp(p, "Imm", 3))  { e[ea_Imm]  = setting; p = p+3;
	  } else {
	    fprintf(stderr, "%d: unknown qualifier for EA\n", lineno);
	    exit(1);
	  }
	} while (*p++ == ',');
	if (*(p-1) != ')') {
	  fprintf(stderr, "%d: unknown qualifier for EA\n", lineno);
	  exit(1);
	}
	break;
      case 'f':
	expand_d_ea_f = 1;

	if (*p++ != '(') {
	  fprintf(stderr, "%d: missing qualifier for EA\n", lineno);
	  exit(1);
	}
	do {
	  setting = 1;
	  if (*p == '-') {
	    p++;
	    setting = 0;
	  }
	  if (!strncmp(p, "*", 1)) {
	    f[ea_Dreg] = f[ea_Areg] = f[ea_Aind] = f[ea_Ainc] = setting;
	    f[ea_Adec] = f[ea_Adis] = f[ea_Aidx] = f[ea_AbsW] = setting;
	    f[ea_AbsL] = f[ea_Pdis] = f[ea_Pidx] = f[ea_Imm] = setting;
	    p = p+1;
	  } else if (!strncmp(p, "Regs", 4)) {
	    f[ea_Dreg] = f[ea_Areg] = setting;
	    p = p+4;
	  } else if (!strncmp(p, "PC", 2)) {
	    f[ea_Pdis] = f[ea_Pidx] = setting;
	    p = p+2;
	  } else if (!strncmp(p, "Amod", 4)) {
	    f[ea_Ainc] = f[ea_Adec] = setting;
	    p = p+4;
	  } else if (!strncmp(p, "Dreg", 4)) { f[ea_Dreg] = setting; p = p+4;
	  } else if (!strncmp(p, "Areg", 4)) { f[ea_Areg] = setting; p = p+4;
	  } else if (!strncmp(p, "Aind", 4)) { f[ea_Aind] = setting; p = p+4;
	  } else if (!strncmp(p, "Ainc", 4)) { f[ea_Ainc] = setting; p = p+4;
	  } else if (!strncmp(p, "Adec", 4)) { f[ea_Adec] = setting; p = p+4;
	  } else if (!strncmp(p, "Adis", 4)) { f[ea_Adis] = setting; p = p+4;
	  } else if (!strncmp(p, "Aidx", 4)) { f[ea_Aidx] = setting; p = p+4;
	  } else if (!strncmp(p, "AbsW", 4)) { f[ea_AbsW] = setting; p = p+4;
	  } else if (!strncmp(p, "AbsL", 4)) { f[ea_AbsL] = setting; p = p+4;
	  } else if (!strncmp(p, "Pdis", 4)) { f[ea_Pdis] = setting; p = p+4;
	  } else if (!strncmp(p, "Pidx", 4)) { f[ea_Pidx] = setting; p = p+4;
	  } else if (!strncmp(p, "Imm", 3))  { f[ea_Imm]  = setting; p = p+3;
	  } else {
	    fprintf(stderr, "%d: unknown qualifier for EA\n", lineno);
	    exit(1);
	  }
	} while (*p++ == ',');
	if (*(p-1) != ')') {
	  fprintf(stderr, "%d: unknown qualifier for EA\n", lineno);
	  exit(1);
	}
	break;
      default:
	fprintf(stderr, "%d: did not understand dest operand\n", lineno);
	exit(1);
      }
    }
  }
  if (*p != '\0') {
    fprintf(stderr, "%d: no end-of-line found at end of line\n", lineno);
    exit(1);
  }

  /* checks */

  if (expand_d_ea_e) {
    /* BTST is weirdo and you can do BTST Dx, #nnnn where Dx is the source
     * of the bit-position and #nnnn is the immediate data to test */
    if (e[ea_Imm] && mnemonic_num != i_BTST ) {
      fprintf(stderr, "%d: Immediate data not allowed as dest\n", lineno);
      exit(1);
    }
  } 

  if (expand_d_ea_f) {
    if (f[ea_Imm]) {
      fprintf(stderr, "%d: Immediate data not allowed as dest\n", lineno);
      exit(1);
    }
  } 

  if ((num[bite] && !num[bitE]) || (num[bitE] && !num[bite])) {
    fprintf(stderr, "%d: There must be both eee and EEE\n", lineno);
    exit(1);
  }

  if ((num[bitf] && !num[bitF]) || (num[bitF] && !num[bitf])) {
    fprintf(stderr, "%d: There must be both fff and FFF\n", lineno);
    exit(1);
  }

  if (num[bitf] && !expand_d_ea_f) {
    fprintf(stderr, "%d: EA 'f' found but not used in description!\n", lineno);
    exit(1);
  }

  if (num[bite] && expand_d_ea_e && expand_s_ea_e) {
    fprintf(stderr, "%d: EA used as both source and destination!\n", lineno);
    exit(1);
  }

  /* ok, now write to the output a structure for each line we're going to
     do a CPU emulation routine for - this means we will expand anything
     that might require control flow statements, e.g. EA and size bit
     sections but not registers and immediate data that can be done in a
     single instruction-wide '&' (and) statement. */

  /* convert size/EA bits to static */

  {
    t_size size;
    t_datatype ea_e;
    t_datatype ea_f;
    int cc;
    int wordlen, type;
    int idx;

    /* loop through 3 different sizes or just once if no size to loop on */

    for (size = isize;
	 (size == isize) || (num[bitz] && (size <= sz_long)); size++) {

      /* loop through 'e' EA or just once if no EA 'e' to loop on */

      for (ea_e = ea_Dreg;
	   (ea_e == ea_Dreg) || (num[bite] && (ea_e <= ea_Imm)); ea_e++) {

	/* loop through 'f' EA or just once if no EA 'e' to loop on */

	for (ea_f = ea_Dreg;
	     (ea_f == ea_Dreg) || (num[bitf] && (ea_f <= ea_Imm)); ea_f++) {

	  for (cc = 0; (cc == 0) || (num[bitc] && (cc < 16)); cc++) {

	    if (cc == 1)
	      continue;

	    if ((size == sz_none) && num[bitz])
	      continue;

	    /* deal with size */

	    if (num[bitz]) {
	      /* set mask where zz is */
	      mask |= (3<<start[bitz]);
	      /* clear bits where zz is */
	      bits &= ~(3<<start[bitz]);
	      /* set correct value into where zz is */
	      switch (size) {
	      case sz_byte: break;
	      case sz_word: bits |= (1<<start[bitz]); break;
	      case sz_long: bits |= (2<<start[bitz]); break;
	      default:
		printf("%d: Invalid size\n", lineno);
		continue;
	      }
	      if (expand_s_immsize) {
		/* source immediate data depends on size of instruction */
		switch (size) {
		case sz_byte: stype = dt_ImmB; break;
		case sz_word: stype = dt_ImmW; break;
		case sz_long: stype = dt_ImmL; break;
		default:
		  printf("%d: Invalid size\n", lineno);
		  exit(1);
		}
	      }
	    }

	    /* deal with cc */

	    if (num[bitc]) {
	      /* set mask where cccc is */
	      mask |= (15<<start[bitc]);
	      /* clear bits where cccc is */
	      bits &= ~(15<<start[bitc]);
	      /* set correct value into where cccc is */
	      bits |= cc<<start[bitc];
	    }
	    
	    /* deal with EA 'e' when used as source */
	    
	    if (num[bite] && expand_s_ea_e) {
	      if (!e[ea_e]) {
		/* this has been disabled using -Axyz */
		continue;
	      }
	      /* clear everything */
	      mask |= (7<<start[bite]);  /* set mask for eee */
	      mask &= ~(7<<start[bitE]); /* clear mask for EEE */
	      bits &= ~(7<<start[bite]); /* clear bits in eee */
	      bits &= ~(7<<start[bitE]); /* clear bits in EEE */
	      if (ea_e <= ea_Aidx) {
		/* ea mode with register in second part */
		bits |= (ea_e<<start[bite]);
		switch (ea_e) {
		case ea_Dreg: stype = dt_Dreg; sbitpos = start[bitE]; break;
		case ea_Areg: stype = dt_Areg; sbitpos = start[bitE]; break;
		case ea_Aind: stype = dt_Aind; sbitpos = start[bitE]; break;
		case ea_Ainc: stype = dt_Ainc; sbitpos = start[bitE]; break;
		case ea_Adec: stype = dt_Adec; sbitpos = start[bitE]; break;
		case ea_Adis: stype = dt_Adis; sbitpos = start[bitE]; break;
		case ea_Aidx: stype = dt_Aidx; sbitpos = start[bitE]; break;
		default: abort();
		}
	      } else {
		bits |= (7<<start[bite]); /* eee should be 111 */
		mask |= (7<<start[bitE]);
		switch (ea_e) {
		case ea_AbsW: stype = dt_AbsW; bits |= (0<<start[bitE]); break;
		case ea_AbsL: stype = dt_AbsL; bits |= (1<<start[bitE]); break;
		case ea_Pdis: stype = dt_Pdis; bits |= (2<<start[bitE]); break;
		case ea_Pidx: stype = dt_Pidx; bits |= (3<<start[bitE]); break;
		case ea_Imm:
		  bits |= (4<<start[bitE]);
		  switch (size) {
		  case sz_byte: stype = dt_ImmB; break;
		  case sz_word: stype = dt_ImmW; break;
		  case sz_long: stype = dt_ImmL; break;
		  default:
		    printf("%d: Invalid size\n", lineno);
		    exit(1);
		  }
		  break;
		default: abort();
		}
	      }
	    }
	    
	    /* deal with EA 'e' when used as destination */
	    
	    if (num[bite] && expand_d_ea_e) {
	      if (!e[ea_e]) {
		/* this has been disabled using -Axyz */
		continue;
	      }
	      /* clear everything */
	      mask |= (7<<start[bite]);  /* set mask for eee */
	      mask &= ~(7<<start[bitE]); /* clear mask for EEE */
	      bits &= ~(7<<start[bite]); /* clear bits in eee */
	      bits &= ~(7<<start[bitE]); /* clear bits in EEE */
	      if (ea_e <= ea_Aidx) {
		/* ea mode with register in second part */
		bits |= (ea_e<<start[bite]);
		switch (ea_e) {
		case ea_Dreg: dtype = dt_Dreg; dbitpos = start[bitE]; break;
		case ea_Areg: dtype = dt_Areg; dbitpos = start[bitE]; break;
		case ea_Aind: dtype = dt_Aind; dbitpos = start[bitE]; break;
		case ea_Ainc: dtype = dt_Ainc; dbitpos = start[bitE]; break;
		case ea_Adec: dtype = dt_Adec; dbitpos = start[bitE]; break;
		case ea_Adis: dtype = dt_Adis; dbitpos = start[bitE]; break;
		case ea_Aidx: dtype = dt_Aidx; dbitpos = start[bitE]; break;
		default: abort();
		}
	      } else {
		bits |= (7<<start[bite]); /* eee should be 111 */
		mask |= (7<<start[bitE]);
		switch (ea_e) {
		case ea_AbsW: dtype = dt_AbsW; bits |= (0<<start[bitE]); break;
		case ea_AbsL: dtype = dt_AbsL; bits |= (1<<start[bitE]); break;
		case ea_Pdis: dtype = dt_Pdis; bits |= (2<<start[bitE]); break;
		case ea_Pidx: dtype = dt_Pidx; bits |= (3<<start[bitE]); break;
		case ea_Imm:
		  bits |= (4<<start[bitE]);
		  switch (size) {
		  case sz_byte: dtype = dt_ImmB; break;
		  case sz_word: dtype = dt_ImmW; break;
		  case sz_long: dtype = dt_ImmL; break;
		  default:
		    printf("%d: Invalid size\n", lineno);
		    exit(1);
		  }
		  break;
		default: abort();
		}
	      }
	    }
	    
	    /* deal with EA 'f' when used as destination */
	    
	    if (num[bitf] && expand_d_ea_f) {
	      if (!f[ea_f]) {
		/* this has been disabled using -Axyz */
		continue;
	      }
	      /* clear everything */
	      mask |= (7<<start[bitf]);  /* set mask for fff */
	      mask &= ~(7<<start[bitF]); /* clear mask for FFF */
	      bits &= ~(7<<start[bitf]); /* clear bits in fff */
	      bits &= ~(7<<start[bitF]); /* clear bits in FFF */
	      if (ea_f <= ea_Aidx) {
		/* ea mode with register in second part */
		bits |= (ea_f<<start[bitf]);
		switch (ea_f) {
		case ea_Dreg: dtype = dt_Dreg; dbitpos = start[bitF]; break;
		case ea_Areg: dtype = dt_Areg; dbitpos = start[bitF]; break;
		case ea_Aind: dtype = dt_Aind; dbitpos = start[bitF]; break;
		case ea_Ainc: dtype = dt_Ainc; dbitpos = start[bitF]; break;
		case ea_Adec: dtype = dt_Adec; dbitpos = start[bitF]; break;
		case ea_Adis: dtype = dt_Adis; dbitpos = start[bitF]; break;
		case ea_Aidx: dtype = dt_Aidx; dbitpos = start[bitF]; break;
		default: abort();
		}
	      } else {
		bits |= (7<<start[bitf]); /* eee should be 111 */
		mask |= (7<<start[bitF]);
		switch (ea_f) {
		case ea_AbsW: dtype = dt_AbsW; bits |= (0<<start[bitF]); break;
		case ea_AbsL: dtype = dt_AbsL; bits |= (1<<start[bitF]); break;
		case ea_Pdis: dtype = dt_Pdis; bits |= (2<<start[bitF]); break;
		case ea_Pidx: dtype = dt_Pidx; bits |= (3<<start[bitF]); break;
		case ea_Imm:
		  bits |= (4<<start[bitF]);
		  switch (size) {
		  case sz_byte: dtype = dt_ImmB; break;
		  case sz_word: dtype = dt_ImmW; break;
		  case sz_long: dtype = dt_ImmL; break;
		  default:
		    printf("%d: Invalid size\n", lineno);
		    exit(1);
		  }
		  break;
		default: abort();
		}
	      }
	    }

	    wordlen = 1;
	    for (type = 0; type < 2; type++) {
	      switch(type ? stype : dtype) {
	      case dt_Ill:
	      case dt_Dreg:
	      case dt_Areg:
	      case dt_Aind:
	      case dt_Ainc:
	      case dt_Adec:
		break;
	      case dt_Adis:
	      case dt_Aidx:
	      case dt_AbsW:
	      case dt_Pdis:
	      case dt_Pidx:
	      case dt_ImmB:
	      case dt_ImmW:
		wordlen++;
		break;
	      case dt_AbsL:
	      case dt_ImmL:
		wordlen+= 2;
		break;
	      case dt_ImmS:
	      case dt_Imm3:
	      case dt_Imm4:
	      case dt_Imm8:
	      case dt_Imm8s:
	      case dt_ImmV:
		break;
	      default:
		printf("%d: Invalid type\n", lineno);
		exit(1);
	      }
	    }

	    /* BUG: The immediate instructions are probably not correct,
	       e.g. ADDI, ADDQ, ANDI, CMPI, EORI, MOVEQ, ORI, SUBI, SUBQ */

	    clocks = -1;

	    switch(mnemonic_num) {
	    case i_EOR:
	      if (dtype == dt_Dreg) {
		clocks = size != sz_long ? 4 : 8;
		clocks+= clocks_eacalc(stype, size);
	      } else if (stype == dt_Dreg) {
		clocks = size != sz_long ? 8 : 12;
		clocks+= clocks_eacalc(dtype, size);
	      } else {
		clocks = size != sz_long ? 20 : 12;
		clocks+= clocks_eacalc(dtype, size);
	      }
	      break;
	    case i_OR:
	    case i_AND:
	      if (dtype == dt_Dreg) {
		clocks = size != sz_long ? 4 : clocks_6or8(stype);
		clocks+= clocks_eacalc(stype, size);
	      } else if (stype == dt_Dreg) {
		clocks = size != sz_long ? 8 : 12;
		clocks+= clocks_eacalc(dtype, size);
	      } else {
		clocks = size != sz_long ? 20 : 12;
		clocks+= clocks_eacalc(dtype, size);
	      }
	      break;
	    case i_ADDA:
	    case i_SUBA:
	      if (dtype == dt_Areg) {
		clocks = size != sz_long ? 8 : clocks_6or8(stype);
		clocks+= clocks_eacalc(stype, size);
	      } else {
		printf("%d: clock count invalid type\n", lineno);
		exit(1);
	      }
	      break;
	    case i_ADD:
	    case i_SUB:
	      if (dtype == dt_Dreg) {
		clocks = size != sz_long ? 4 : clocks_6or8(stype);
		clocks+= clocks_eacalc(stype, size);
	      } else if (stype == dt_Dreg) {
		clocks = size != sz_long ? 8 : 12;
		clocks+= clocks_eacalc(dtype, size);
	      } else {
		clocks = size != sz_long ? 20 : 12;
		clocks+= clocks_eacalc(dtype, size);
	      }
	      break;
	    case i_CMP:
	    case i_CMPA:
	      if (dtype == dt_Areg) {
		clocks = 6;
		clocks+= clocks_eacalc(stype, size);
	      } else if (dtype == dt_Dreg) {
		clocks = size != sz_long ? 4 : 6;
		clocks+= clocks_eacalc(stype, size);
	      } else { /* CMPM */
		clocks = 12 + clocks_eacalc(stype, size) +
		  clocks_eacalc(dtype, size);
	      }
	      break;
	    case i_DIVS:
	      clocks = 158 - 8 + clocks_eacalc(stype, size);
	      break;
	    case i_DIVU:
	      clocks = 140 - 8 + clocks_eacalc(stype, size);
	      break;
	    case i_MULS:
	      clocks = 38 + clocks_eacalc(stype, size);
	      break;
	    case i_MULU:
	      clocks = 38 + clocks_eacalc(stype, size);
	      break;
	    case i_MOVE:
	    case i_MOVEA:
	      if ((idx = clocks_typetoindex(dtype)) == -1) {
		printf("%d: clock count invalid MOVE type\n", lineno);
		exit(1);
	      }
	      clocks = clocks_movetable[clocks_typetoindex(stype)*9+idx];
	      break;
	    case i_CLR:
	    case i_NEG:
	    case i_NEGX:
	    case i_NOT:
	      if (stype == dt_Dreg || stype == dt_Areg) {
		clocks = size != sz_long ? 4 : 6;
	      } else {
		clocks = size != sz_long ? 8 : 12;
		clocks+= clocks_eacalc(stype, size);
	      }
	      break;
	    case i_NBCD:
	      if (stype == dt_Dreg || stype == dt_Areg) {
		clocks = 6;
	      } else {
		clocks = 8 + clocks_eacalc(stype, size);
	      }
	      break;
	    case i_Scc:
	    case i_SF:
	      if (stype == dt_Dreg || stype == dt_Areg) {
		clocks = size != sz_long ? 4 : 6;
	      } else {
		clocks = 8 + clocks_eacalc(stype, size);
	      }
	      break;
	    case i_TAS:
	      if (stype == dt_Dreg || stype == dt_Areg) {
		clocks = 4;
	      } else {
		clocks = 10 + clocks_eacalc(stype, size);
	      }
	      break;
	    case i_TST:
	      if (stype == dt_Dreg || stype == dt_Areg) {
		clocks = 4;
	      } else {
		clocks = 4 + clocks_eacalc(stype, size);
	      }
	      break;
	    case i_ASR:
	    case i_ASL:
	    case i_LSR:
	    case i_LSL:
	    case i_ROR:
	    case i_ROL:
	    case i_ROXR:
	    case i_ROXL:
	      if (stype == dt_Dreg || stype == dt_Areg) {
		clocks = size != sz_long ? 8 : 10; /* minimums */
	      } else {
		clocks = 8 + clocks_eacalc(stype, size);
	      }
	      break;
	    case i_BCHG:
	    case i_BSET:
	      if (stype == dt_Dreg) { /* dynamic */
		clocks = (dtype == dt_Dreg) ? 8 : 8 +
		  clocks_eacalc(stype, size);
	      } else { /* static */
		clocks = (dtype == dt_Dreg) ? 14 : 12 +
		  clocks_eacalc(stype, size);
	      }
	    case i_BCLR:
	      if (stype == dt_Dreg) { /* dynamic */
		clocks = (dtype == dt_Dreg) ? 10 : 8 +
		  clocks_eacalc(stype, size);
	      } else { /* static */
		clocks = (dtype == dt_Dreg) ? 14 : 12 +
		  clocks_eacalc(stype, size);
	      }
	      break;
	    case i_BTST:
	      if (stype == dt_Dreg) { /* dynamic */
		clocks = (dtype == dt_Dreg) ? 6 : 4 +
		  clocks_eacalc(stype, size);
	      } else { /* static */
		clocks = (dtype == dt_Dreg) ? 10 : 8 +
		  clocks_eacalc(stype, size);
	      }
	      break;
	    case i_JMP:
	      switch(stype) {
	      case dt_Aind: clocks =  8; break;
	      case dt_Adis: clocks = 10; break;
	      case dt_Aidx: clocks = 14; break;
	      case dt_AbsW: clocks = 10; break;
	      case dt_AbsL: clocks = 12; break;
	      case dt_Pdis: clocks = 10; break;
	      case dt_Pidx: clocks = 14; break;
	      default:
		printf("%d: clock count invalid type\n", lineno);
		exit(1);
	      }
	      break;
	    case i_JSR:
	      switch(stype) {
	      case dt_Aind: clocks = 16; break;
	      case dt_Adis: clocks = 18; break;
	      case dt_Aidx: clocks = 22; break;
	      case dt_AbsW: clocks = 18; break;
	      case dt_AbsL: clocks = 20; break;
	      case dt_Pdis: clocks = 18; break;
	      case dt_Pidx: clocks = 22; break;
	      default:
		printf("%d: clock count invalid type\n", lineno);
		exit(1);
	      }
	      break;
	    case i_LEA:
	      switch(stype) {
	      case dt_Aind: clocks =  4; break;
	      case dt_Adis: clocks =  8; break;
	      case dt_Aidx: clocks = 12; break;
	      case dt_AbsW: clocks =  8; break;
	      case dt_AbsL: clocks = 12; break;
	      case dt_Pdis: clocks =  8; break;
	      case dt_Pidx: clocks = 12; break;
	      default:
		printf("%d: clock count invalid type\n", lineno);
		exit(1);
	      }
	      break;
	    case i_PEA:
	      switch(stype) {
	      case dt_Aind: clocks = 12; break;
	      case dt_Adis: clocks = 16; break;
	      case dt_Aidx: clocks = 20; break;
	      case dt_AbsW: clocks = 16; break;
	      case dt_AbsL: clocks = 20; break;
	      case dt_Pdis: clocks = 16; break;
	      case dt_Pidx: clocks = 20; break;
	      default:
		printf("%d: clock count invalid type\n", lineno);
		exit(1);
	      }
	      break;
	    case i_MOVEMMR:
	      clocks = 20;
	      break;
	    case i_MOVEMRM:
	      clocks = 16;
	      break;
	    case i_SUBX:
	    case i_ADDX:
	      if (stype == dt_Dreg) {
		clocks = size != sz_long ? 4 : 8;
	      } else {
		clocks = size != sz_long ? 18 : 30;
	      }
	      break;
	    case i_ABCD:
	    case i_SBCD:
	      clocks = (stype == dt_Dreg) ? 6 : 18;
	      break;
	    case i_ORSR:
	    case i_ANDSR:
	    case i_EORSR:
	      clocks = 20;
	      break;
	    case i_CHK:
	      clocks = 10 + clocks_eacalc(stype, size);
	      break;
	    case i_EXG:
	      clocks = 6;
	      break;
	    case i_EXT:
	      clocks = 4;
	      break;
	    case i_LINK:
	      clocks = 16;
	      break;
	    case i_MOVEFSR:
	      clocks = (stype == dt_Dreg) ? 6 : 8 + clocks_eacalc(stype, size);
	      break;
	    case i_MOVETSR:
	      clocks = (stype == dt_Dreg) ? 12 : 12 +
		clocks_eacalc(stype, size);
	      break;
	    case i_MOVETUSP:
	    case i_MOVEFUSP:
	      clocks = 4;
	      break;
	    case i_NOP:
	      clocks = 4;
	      break;
	    case i_RESET:
	      clocks = 132;
	      break;
	    case i_RTE:
	    case i_RTR:
	      clocks = 20;
	      break;
	    case i_RTS:
	      clocks = 20;
	      break;
	    case i_STOP:
	      clocks = 4;
	      break;
	    case i_SWAP:
	      clocks = 4;
	      break;
	    case i_TRAPV:
	      clocks = 4;
	      break;
	    case i_TRAP:
	      clocks = 4; /* exception */
	      break;
	    case i_UNLK:
	      clocks = 12;
	      break;
	    case i_DBcc:
	    case i_DBRA:
	    case i_Bcc:
	      clocks = 10;
	      break;
	    case i_BSR:
	      clocks = 18;
	      break;
	    case i_MOVEPRM:
	    case i_MOVEPMR:
	      clocks = (size != sz_long) ? 16 : 24;
	      break;
	    case i_ILLG:
	      clocks = 0;
	      break;
	    case i_LINE10:
	    case i_LINE15:
	      clocks = 4; /* exception */
	      break;
	    default:
	      printf("%d: Invalid mnemonic type\n", lineno);
	      exit(1);
	    }

	    if (clocks == -1) {
	      printf("%d: Clocks not found\n", lineno);
	      exit(1);
	    }

	    /* write output lines */
	    
	    fprintf(outiibs, "  { 0x%x, 0x%x, %d, { %d, %d, %d, %d, %d }, ",
		    mask, bits, mnemonic_num, priv, endblk, imm_notzero, used,
		    set);
	    fprintf(outiibs, "%d, %d, %d, %d, %d, %d, %d, %d, %d, %d},\n",
		    size, stype, dtype, sbitpos, dbitpos, immvalue,
		    cc, total, wordlen, clocks);
	    fprintf(outiibs, "%60s/* %s */\n", "", mnemonic);
	    if (set == 0) {
	      fprintf(outfuncs, "  cpu_op_%ia, /* %s */\n", total, mnemonic);
	      fprintf(outfuncs, "  cpu_op_%ia, /* %s */\n", total, mnemonic);
	      fprintf(outproto, "extern void cpu_op_%ia("
		      "t_ipc *ipc); /* %s */\n", total, mnemonic);
	    } else {
	      fprintf(outfuncs, "  cpu_op_%ia, /* %s - normal */\n", total,
		      mnemonic);
	      fprintf(outfuncs, "  cpu_op_%ib, /* %s - no flags */\n", total,
		      mnemonic);
	      fprintf(outproto, "extern void cpu_op_%ia("
		      "t_ipc *ipc); /* %s */\n", total, mnemonic);
	      fprintf(outproto, "extern void cpu_op_%ib("
		      "t_ipc *ipc); /* %s */\n", total, mnemonic);
	    }
	    
	    total++;

	  } /* cc */
	} /* ea_f */
      } /* ea_e */
    } /* size */
  } /* block */
}

int clocks_movetable[] = {
   4,   4,  8,  8,  8, 12, 14, 12, 16,
   4,   4,  8,  8,  8, 12, 14, 12, 16,
   8,   8, 12, 12, 12, 16, 18, 16, 20,
   8,   8, 12, 12, 12, 16, 18, 16, 20,
   10, 10, 14, 14, 14, 18, 20, 18, 22,
   12, 12, 16, 16, 16, 20, 22, 20, 24,
   14, 14, 18, 18, 18, 22, 24, 22, 26,
   12, 12, 16, 16, 16, 20, 22, 20, 24,
   16, 16, 20, 20, 20, 24, 26, 24, 28,
   12, 12, 16, 16, 16, 20, 22, 20, 24,
   14, 14, 18, 18, 18, 22, 24, 22, 26,
    8,  8, 12, 12, 12, 16, 18, 16, 20
};

int clocks_typetoindex(t_datatype type)
{
  switch(type) {
  case dt_Dreg: return 0;
  case dt_Areg: return 1;
  case dt_Aind: return 2;
  case dt_Ainc: return 3;
  case dt_Adec: return 4;
  case dt_Adis: return 5;
  case dt_Aidx: return 6;
  case dt_AbsW: return 7;
  case dt_AbsL: return 8;
  case dt_Pdis: return 9;
  case dt_Pidx: return 10;
  case dt_ImmB:
  case dt_ImmW:
  case dt_ImmL:
  case dt_ImmS:
  case dt_Imm3:
  case dt_Imm4:
  case dt_Imm8:
  case dt_Imm8s: return 11;
  default:
    break;
  }
  printf("Invalid type for clocks\n");
  exit(1);
}

int clocks_eacalc(t_datatype type, t_size size)
{
  switch(type) {
  case dt_Dreg:
  case dt_Areg: return 0;
  case dt_Aind: return (size != sz_long) ? 4 : 8;
  case dt_Ainc: return (size != sz_long) ? 6 : 10; /* should this be 4/8? */
  case dt_Adec: return (size != sz_long) ? 6 : 10;
  case dt_Adis: return (size != sz_long) ? 8 : 12;
  case dt_Aidx: return (size != sz_long) ? 10 : 14;
  case dt_AbsW: return (size != sz_long) ? 8 : 12;
  case dt_AbsL: return (size != sz_long) ? 12 : 16;
  case dt_Pdis: return (size != sz_long) ? 8 : 12;
  case dt_Pidx: return (size != sz_long) ? 10 : 14;
  case dt_ImmB:
  case dt_ImmW:
  case dt_ImmL: return (size != sz_long) ? 4 : 8;
  case dt_ImmS:
  case dt_Imm3:
  case dt_Imm4:
  case dt_Imm8:
  case dt_Imm8s:
  case dt_ImmV:
  case dt_Ill: return 0;
  }
  printf("Invalid type for clocks\n");
  exit(1);
}

int clocks_6or8(t_datatype type)
{
  int type_imm = (type == dt_ImmB) || (type == dt_ImmW) ||
    (type == dt_ImmL) || (type == dt_Imm3) || (type == dt_Imm4) ||
    (type == dt_Imm8) || (type == dt_Imm8s) || (type == dt_ImmS);

  return (type_imm || type == dt_Dreg || type == dt_Areg) ? 8 : 6;
}
