199461Sobrien/* s390-mkopc.c -- Generates opcode table out of s390-opc.txt
2218822Sdim   Copyright 2000, 2001, 2003 Free Software Foundation, Inc.
399461Sobrien   Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
499461Sobrien
599461Sobrien   This file is part of GDB, GAS, and the GNU binutils.
699461Sobrien
799461Sobrien   This program is free software; you can redistribute it and/or modify
899461Sobrien   it under the terms of the GNU General Public License as published by
999461Sobrien   the Free Software Foundation; either version 2 of the License, or
1099461Sobrien   (at your option) any later version.
1199461Sobrien
1299461Sobrien   This program is distributed in the hope that it will be useful,
1399461Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1499461Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1599461Sobrien   GNU General Public License for more details.
1699461Sobrien
1799461Sobrien   You should have received a copy of the GNU General Public License
1899461Sobrien   along with this program; if not, write to the Free Software
19218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
20218822Sdim   02110-1301, USA.  */
2199461Sobrien
2299461Sobrien#include <stdio.h>
2399461Sobrien#include <stdlib.h>
2499461Sobrien#include <string.h>
2599461Sobrien
26130561Sobrien/* Taken from opcodes/s390.h */
27130561Sobrienenum s390_opcode_mode_val
28130561Sobrien  {
29130561Sobrien    S390_OPCODE_ESA = 0,
30130561Sobrien    S390_OPCODE_ZARCH
31130561Sobrien  };
3299461Sobrien
33130561Sobrienenum s390_opcode_cpu_val
34130561Sobrien  {
35130561Sobrien    S390_OPCODE_G5 = 0,
36130561Sobrien    S390_OPCODE_G6,
37130561Sobrien    S390_OPCODE_Z900,
38218822Sdim    S390_OPCODE_Z990,
39218822Sdim    S390_OPCODE_Z9_109,
40218822Sdim    S390_OPCODE_Z9_EC
41130561Sobrien  };
42130561Sobrien
4399461Sobrienstruct op_struct
4499461Sobrien  {
4599461Sobrien    char  opcode[16];
4699461Sobrien    char  mnemonic[16];
4799461Sobrien    char  format[16];
48130561Sobrien    int   mode_bits;
49130561Sobrien    int   min_cpu;
50130561Sobrien
5199461Sobrien    unsigned long long sort_value;
5299461Sobrien    int   no_nibbles;
5399461Sobrien  };
5499461Sobrien
5599461Sobrienstruct op_struct *op_array;
5699461Sobrienint max_ops;
5799461Sobrienint no_ops;
5899461Sobrien
5999461Sobrienstatic void
6099461SobriencreateTable (void)
6199461Sobrien{
6299461Sobrien  max_ops = 256;
6399461Sobrien  op_array = malloc (max_ops * sizeof (struct op_struct));
6499461Sobrien  no_ops = 0;
6599461Sobrien}
6699461Sobrien
6799461Sobrien/* `insertOpcode': insert an op_struct into sorted opcode array.  */
6899461Sobrien
6999461Sobrienstatic void
70130561SobrieninsertOpcode (char *opcode, char *mnemonic, char *format,
71130561Sobrien	      int min_cpu, int mode_bits)
7299461Sobrien{
7399461Sobrien  char *str;
7499461Sobrien  unsigned long long sort_value;
7599461Sobrien  int no_nibbles;
7699461Sobrien  int ix, k;
7799461Sobrien
7899461Sobrien  while (no_ops >= max_ops)
7999461Sobrien    {
8099461Sobrien      max_ops = max_ops * 2;
8199461Sobrien      op_array = realloc (op_array, max_ops * sizeof (struct op_struct));
8299461Sobrien    }
8399461Sobrien
8499461Sobrien  sort_value = 0;
8599461Sobrien  str = opcode;
8699461Sobrien  for (ix = 0; ix < 16; ix++)
8799461Sobrien    {
8899461Sobrien      if (*str >= '0' && *str <= '9')
8999461Sobrien	sort_value = (sort_value << 4) + (*str - '0');
9099461Sobrien      else if (*str >= 'a' && *str <= 'f')
9199461Sobrien	sort_value = (sort_value << 4) + (*str - 'a' + 10);
9299461Sobrien      else if (*str >= 'A' && *str <= 'F')
9399461Sobrien	sort_value = (sort_value << 4) + (*str - 'A' + 10);
9499461Sobrien      else if (*str == '?')
9599461Sobrien	sort_value <<= 4;
9699461Sobrien      else
9799461Sobrien	break;
9899461Sobrien      str ++;
9999461Sobrien    }
10099461Sobrien  sort_value <<= 4*(16 - ix);
101130561Sobrien  sort_value += (min_cpu << 8) + mode_bits;
10299461Sobrien  no_nibbles = ix;
10399461Sobrien  for (ix = 0; ix < no_ops; ix++)
10499461Sobrien    if (sort_value > op_array[ix].sort_value)
10599461Sobrien      break;
10699461Sobrien  for (k = no_ops; k > ix; k--)
10799461Sobrien    op_array[k] = op_array[k-1];
10899461Sobrien  strcpy(op_array[ix].opcode, opcode);
10999461Sobrien  strcpy(op_array[ix].mnemonic, mnemonic);
11099461Sobrien  strcpy(op_array[ix].format, format);
11199461Sobrien  op_array[ix].sort_value = sort_value;
11299461Sobrien  op_array[ix].no_nibbles = no_nibbles;
113130561Sobrien  op_array[ix].min_cpu = min_cpu;
114130561Sobrien  op_array[ix].mode_bits = mode_bits;
11599461Sobrien  no_ops++;
11699461Sobrien}
11799461Sobrien
11899461Sobrienstatic char file_header[] =
11999461Sobrien  "/* The opcode table. This file was generated by s390-mkopc.\n\n"
12099461Sobrien  "   The format of the opcode table is:\n\n"
12199461Sobrien  "   NAME	     OPCODE	MASK	OPERANDS\n\n"
12299461Sobrien  "   Name is the name of the instruction.\n"
12399461Sobrien  "   OPCODE is the instruction opcode.\n"
12499461Sobrien  "   MASK is the opcode mask; this is used to tell the disassembler\n"
12599461Sobrien  "     which bits in the actual opcode must match OPCODE.\n"
12699461Sobrien  "   OPERANDS is the list of operands.\n\n"
12799461Sobrien  "   The disassembler reads the table in order and prints the first\n"
12899461Sobrien  "   instruction which matches.  */\n\n"
12999461Sobrien  "const struct s390_opcode s390_opcodes[] =\n  {\n";
13099461Sobrien
13199461Sobrien/* `dumpTable': write opcode table.  */
13299461Sobrien
13399461Sobrienstatic void
13499461SobriendumpTable (void)
13599461Sobrien{
13699461Sobrien  char *str;
13799461Sobrien  int  ix;
13899461Sobrien
13999461Sobrien  /*  Write hash table entries (slots).  */
14099461Sobrien  printf (file_header);
14199461Sobrien
14299461Sobrien  for (ix = 0; ix < no_ops; ix++)
14399461Sobrien    {
14499461Sobrien      printf ("  { \"%s\", ", op_array[ix].mnemonic);
14599461Sobrien      for (str = op_array[ix].opcode; *str != 0; str++)
14699461Sobrien	if (*str == '?')
14799461Sobrien	  *str = '0';
14899461Sobrien      printf ("OP%i(0x%sLL), ",
14999461Sobrien	      op_array[ix].no_nibbles*4, op_array[ix].opcode);
15099461Sobrien      printf ("MASK_%s, INSTR_%s, ",
15199461Sobrien	      op_array[ix].format, op_array[ix].format);
152130561Sobrien      printf ("%i, ", op_array[ix].mode_bits);
153130561Sobrien      printf ("%i}", op_array[ix].min_cpu);
15499461Sobrien      if (ix < no_ops-1)
15599461Sobrien	printf (",\n");
15699461Sobrien      else
15799461Sobrien	printf ("\n");
15899461Sobrien    }
15999461Sobrien  printf ("};\n\n");
16099461Sobrien  printf ("const int s390_num_opcodes =\n");
16199461Sobrien  printf ("  sizeof (s390_opcodes) / sizeof (s390_opcodes[0]);\n\n");
16299461Sobrien}
16399461Sobrien
16499461Sobrienint
16599461Sobrienmain (void)
16699461Sobrien{
16799461Sobrien  char currentLine[256];
16899461Sobrien
16999461Sobrien  createTable ();
17099461Sobrien
17199461Sobrien  /*  Read opcode descriptions from `stdin'.  For each mnemonic,
17299461Sobrien      make an entry into the opcode table.  */
17399461Sobrien  while (fgets (currentLine, sizeof (currentLine), stdin) != NULL)
17499461Sobrien    {
17599461Sobrien      char  opcode[16];
17699461Sobrien      char  mnemonic[16];
17799461Sobrien      char  format[16];
17899461Sobrien      char  description[64];
179130561Sobrien      char  cpu_string[16];
180130561Sobrien      char  modes_string[16];
181130561Sobrien      int   min_cpu;
182130561Sobrien      int   mode_bits;
183130561Sobrien      char  *str;
18499461Sobrien
18599461Sobrien      if (currentLine[0] == '#')
18699461Sobrien        continue;
18799461Sobrien      memset (opcode, 0, 8);
188130561Sobrien      if (sscanf (currentLine, "%15s %15s %15s \"%[^\"]\" %15s %15s",
189130561Sobrien		  opcode, mnemonic, format, description,
190130561Sobrien		  cpu_string, modes_string) == 6)
19199461Sobrien	{
192130561Sobrien	  if (strcmp (cpu_string, "g5") == 0)
193130561Sobrien	    min_cpu = S390_OPCODE_G5;
194130561Sobrien	  else if (strcmp (cpu_string, "g6") == 0)
195130561Sobrien	    min_cpu = S390_OPCODE_G6;
196130561Sobrien	  else if (strcmp (cpu_string, "z900") == 0)
197130561Sobrien	    min_cpu = S390_OPCODE_Z900;
198130561Sobrien	  else if (strcmp (cpu_string, "z990") == 0)
199130561Sobrien	    min_cpu = S390_OPCODE_Z990;
200218822Sdim	  else if (strcmp (cpu_string, "z9-109") == 0)
201218822Sdim	    min_cpu = S390_OPCODE_Z9_109;
202218822Sdim	  else if (strcmp (cpu_string, "z9-ec") == 0)
203218822Sdim	    min_cpu = S390_OPCODE_Z9_EC;
204130561Sobrien	  else {
205130561Sobrien	    fprintf (stderr, "Couldn't parse cpu string %s\n", cpu_string);
206130561Sobrien	    exit (1);
207130561Sobrien	  }
208130561Sobrien
209130561Sobrien	  str = modes_string;
210130561Sobrien	  mode_bits = 0;
211130561Sobrien	  do {
212130561Sobrien	    if (strncmp (str, "esa", 3) == 0
213130561Sobrien		&& (str[3] == 0 || str[3] == ',')) {
214130561Sobrien	      mode_bits |= 1 << S390_OPCODE_ESA;
215130561Sobrien	      str += 3;
216130561Sobrien	    } else if (strncmp (str, "zarch", 5) == 0
217130561Sobrien		       && (str[5] == 0 || str[5] == ',')) {
218130561Sobrien	      mode_bits |= 1 << S390_OPCODE_ZARCH;
219130561Sobrien	      str += 5;
220130561Sobrien	    } else {
221130561Sobrien	      fprintf (stderr, "Couldn't parse modes string %s\n",
222130561Sobrien		       modes_string);
223130561Sobrien	      exit (1);
224130561Sobrien	    }
225130561Sobrien	    if (*str == ',')
226130561Sobrien	      str++;
227130561Sobrien	  } while (*str != 0);
228130561Sobrien	  insertOpcode (opcode, mnemonic, format, min_cpu, mode_bits);
22999461Sobrien	}
23099461Sobrien      else
23199461Sobrien        fprintf (stderr, "Couldn't scan line %s\n", currentLine);
23299461Sobrien    }
23399461Sobrien
23499461Sobrien  dumpTable ();
23599461Sobrien  return 0;
23699461Sobrien}
237