1/* s390-mkopc.c -- Generates opcode table out of s390-opc.txt
2   Copyright 2000, 2001 Free Software Foundation, Inc.
3   Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
4
5   This file is part of GDB, GAS, and the GNU binutils.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20   02111-1307, USA.  */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26/* Taken from opcodes/s390.h */
27enum s390_opcode_mode_val
28  {
29    S390_OPCODE_ESA = 0,
30    S390_OPCODE_ZARCH
31  };
32
33enum s390_opcode_cpu_val
34  {
35    S390_OPCODE_G5 = 0,
36    S390_OPCODE_G6,
37    S390_OPCODE_Z900,
38    S390_OPCODE_Z990
39  };
40
41struct op_struct
42  {
43    char  opcode[16];
44    char  mnemonic[16];
45    char  format[16];
46    int   mode_bits;
47    int   min_cpu;
48
49    unsigned long long sort_value;
50    int   no_nibbles;
51  };
52
53struct op_struct *op_array;
54int max_ops;
55int no_ops;
56
57static void
58createTable (void)
59{
60  max_ops = 256;
61  op_array = malloc (max_ops * sizeof (struct op_struct));
62  no_ops = 0;
63}
64
65/* `insertOpcode': insert an op_struct into sorted opcode array.  */
66
67static void
68insertOpcode (char *opcode, char *mnemonic, char *format,
69	      int min_cpu, int mode_bits)
70{
71  char *str;
72  unsigned long long sort_value;
73  int no_nibbles;
74  int ix, k;
75
76  while (no_ops >= max_ops)
77    {
78      max_ops = max_ops * 2;
79      op_array = realloc (op_array, max_ops * sizeof (struct op_struct));
80    }
81
82  sort_value = 0;
83  str = opcode;
84  for (ix = 0; ix < 16; ix++)
85    {
86      if (*str >= '0' && *str <= '9')
87	sort_value = (sort_value << 4) + (*str - '0');
88      else if (*str >= 'a' && *str <= 'f')
89	sort_value = (sort_value << 4) + (*str - 'a' + 10);
90      else if (*str >= 'A' && *str <= 'F')
91	sort_value = (sort_value << 4) + (*str - 'A' + 10);
92      else if (*str == '?')
93	sort_value <<= 4;
94      else
95	break;
96      str ++;
97    }
98  sort_value <<= 4*(16 - ix);
99  sort_value += (min_cpu << 8) + mode_bits;
100  no_nibbles = ix;
101  for (ix = 0; ix < no_ops; ix++)
102    if (sort_value > op_array[ix].sort_value)
103      break;
104  for (k = no_ops; k > ix; k--)
105    op_array[k] = op_array[k-1];
106  strcpy(op_array[ix].opcode, opcode);
107  strcpy(op_array[ix].mnemonic, mnemonic);
108  strcpy(op_array[ix].format, format);
109  op_array[ix].sort_value = sort_value;
110  op_array[ix].no_nibbles = no_nibbles;
111  op_array[ix].min_cpu = min_cpu;
112  op_array[ix].mode_bits = mode_bits;
113  no_ops++;
114}
115
116static char file_header[] =
117  "/* The opcode table. This file was generated by s390-mkopc.\n\n"
118  "   The format of the opcode table is:\n\n"
119  "   NAME	     OPCODE	MASK	OPERANDS\n\n"
120  "   Name is the name of the instruction.\n"
121  "   OPCODE is the instruction opcode.\n"
122  "   MASK is the opcode mask; this is used to tell the disassembler\n"
123  "     which bits in the actual opcode must match OPCODE.\n"
124  "   OPERANDS is the list of operands.\n\n"
125  "   The disassembler reads the table in order and prints the first\n"
126  "   instruction which matches.  */\n\n"
127  "const struct s390_opcode s390_opcodes[] =\n  {\n";
128
129/* `dumpTable': write opcode table.  */
130
131static void
132dumpTable (void)
133{
134  char *str;
135  int  ix;
136
137  /*  Write hash table entries (slots).  */
138  printf (file_header);
139
140  for (ix = 0; ix < no_ops; ix++)
141    {
142      printf ("  { \"%s\", ", op_array[ix].mnemonic);
143      for (str = op_array[ix].opcode; *str != 0; str++)
144	if (*str == '?')
145	  *str = '0';
146      printf ("OP%i(0x%sLL), ",
147	      op_array[ix].no_nibbles*4, op_array[ix].opcode);
148      printf ("MASK_%s, INSTR_%s, ",
149	      op_array[ix].format, op_array[ix].format);
150      printf ("%i, ", op_array[ix].mode_bits);
151      printf ("%i}", op_array[ix].min_cpu);
152      if (ix < no_ops-1)
153	printf (",\n");
154      else
155	printf ("\n");
156    }
157  printf ("};\n\n");
158  printf ("const int s390_num_opcodes =\n");
159  printf ("  sizeof (s390_opcodes) / sizeof (s390_opcodes[0]);\n\n");
160}
161
162int
163main (void)
164{
165  char currentLine[256];
166
167  createTable ();
168
169  /*  Read opcode descriptions from `stdin'.  For each mnemonic,
170      make an entry into the opcode table.  */
171  while (fgets (currentLine, sizeof (currentLine), stdin) != NULL)
172    {
173      char  opcode[16];
174      char  mnemonic[16];
175      char  format[16];
176      char  description[64];
177      char  cpu_string[16];
178      char  modes_string[16];
179      int   min_cpu;
180      int   mode_bits;
181      char  *str;
182
183      if (currentLine[0] == '#')
184        continue;
185      memset (opcode, 0, 8);
186      if (sscanf (currentLine, "%15s %15s %15s \"%[^\"]\" %15s %15s",
187		  opcode, mnemonic, format, description,
188		  cpu_string, modes_string) == 6)
189	{
190	  if (strcmp (cpu_string, "g5") == 0)
191	    min_cpu = S390_OPCODE_G5;
192	  else if (strcmp (cpu_string, "g6") == 0)
193	    min_cpu = S390_OPCODE_G6;
194	  else if (strcmp (cpu_string, "z900") == 0)
195	    min_cpu = S390_OPCODE_Z900;
196	  else if (strcmp (cpu_string, "z990") == 0)
197	    min_cpu = S390_OPCODE_Z990;
198	  else {
199	    fprintf (stderr, "Couldn't parse cpu string %s\n", cpu_string);
200	    exit (1);
201	  }
202
203	  str = modes_string;
204	  mode_bits = 0;
205	  do {
206	    if (strncmp (str, "esa", 3) == 0
207		&& (str[3] == 0 || str[3] == ',')) {
208	      mode_bits |= 1 << S390_OPCODE_ESA;
209	      str += 3;
210	    } else if (strncmp (str, "zarch", 5) == 0
211		       && (str[5] == 0 || str[5] == ',')) {
212	      mode_bits |= 1 << S390_OPCODE_ZARCH;
213	      str += 5;
214	    } else {
215	      fprintf (stderr, "Couldn't parse modes string %s\n",
216		       modes_string);
217	      exit (1);
218	    }
219	    if (*str == ',')
220	      str++;
221	  } while (*str != 0);
222	  insertOpcode (opcode, mnemonic, format, min_cpu, mode_bits);
223	}
224      else
225        fprintf (stderr, "Couldn't scan line %s\n", currentLine);
226    }
227
228  dumpTable ();
229  return 0;
230}
231