Commit | Line | Data |
---|---|---|
c906108c SS |
1 | /* This file is part of the program psim. |
2 | ||
3 | Copyright (C) 1994,1995,1996, Andrew Cagney <cagney@highland.com.au> | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 2 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
18 | ||
19 | */ | |
20 | ||
21 | /* load the opcode stat structure */ | |
22 | ||
23 | #include "misc.h" | |
24 | #include "lf.h" | |
25 | #include "table.h" | |
26 | #include "filter.h" | |
27 | ||
28 | #include "igen.h" | |
29 | ||
30 | #include "ld-decode.h" | |
31 | ||
32 | #ifndef NULL | |
33 | #define NULL 0 | |
34 | #endif | |
35 | ||
36 | ||
37 | static const name_map decode_type_map[] = { | |
38 | { "normal", normal_decode_rule }, | |
39 | { "boolean", boolean_rule }, | |
40 | { NULL, normal_decode_rule }, | |
41 | }; | |
42 | ||
43 | static const name_map decode_gen_map[] = { | |
44 | { "array", array_gen }, | |
45 | { "switch", switch_gen }, | |
46 | { "padded-switch", padded_switch_gen }, | |
47 | { "goto-switch", goto_switch_gen }, | |
48 | { NULL, -1 }, | |
49 | }; | |
50 | ||
51 | static const name_map decode_reserved_map[] = { | |
52 | { "zero-reserved", 1 }, | |
53 | { NULL, 0 }, | |
54 | }; | |
55 | ||
56 | static const name_map decode_duplicates_map[] = { | |
57 | { "duplicate", 1 }, | |
58 | { NULL, 0 }, | |
59 | }; | |
60 | ||
61 | static const name_map decode_combine_map[] = { | |
62 | { "combine", 1 }, | |
63 | { NULL, 0 }, | |
64 | }; | |
65 | ||
66 | static const name_map decode_search_map[] = { | |
67 | { "constants", decode_find_constants }, | |
68 | { "mixed", decode_find_mixed }, | |
69 | { "strings", decode_find_strings }, | |
70 | { NULL, decode_find_mixed }, | |
71 | }; | |
72 | ||
73 | ||
74 | static void | |
75 | set_bits (int bit[max_insn_bit_size], | |
76 | unsigned64 value) | |
77 | { | |
78 | int bit_nr; | |
79 | for (bit_nr = 0; bit_nr < max_insn_bit_size; bit_nr++) | |
80 | { | |
81 | if (bit_nr < options.insn_bit_size) | |
82 | bit[bit_nr] = (value >> (options.insn_bit_size - bit_nr - 1)) & 1; | |
83 | else | |
84 | bit[bit_nr] = 0; | |
85 | } | |
86 | } | |
87 | ||
88 | decode_table * | |
89 | load_decode_table(char *file_name) | |
90 | { | |
91 | table *file = table_open (file_name); | |
92 | table_entry *entry; | |
93 | decode_table *table = NULL; | |
94 | decode_table **curr_rule = &table; | |
95 | while ((entry = table_read (file)) != NULL) | |
96 | { | |
97 | char *decode_options = entry->field[decode_options_field]; | |
98 | decode_table *new_rule = ZALLOC (decode_table); | |
99 | if (entry->nr_fields < min_nr_decode_fields) | |
100 | error (entry->line, "Missing decode table fields\n"); | |
101 | new_rule->line = entry->line; | |
102 | ||
103 | /* the options field */ | |
104 | new_rule->type = name2i (decode_options, decode_type_map); | |
105 | if (options.decode.overriding_gen != NULL) | |
106 | new_rule->gen = name2i (options.decode.overriding_gen, decode_gen_map); | |
107 | else | |
108 | new_rule->gen = name2i (decode_options, decode_gen_map); | |
109 | if (new_rule->gen == padded_switch_gen | |
110 | && options.decode.switch_as_goto) | |
111 | new_rule->gen = goto_switch_gen; | |
112 | if (options.decode.zero_reserved) | |
113 | new_rule->with_zero_reserved = 1; | |
114 | else | |
115 | new_rule->with_zero_reserved = name2i (decode_options, decode_reserved_map); | |
116 | if (options.decode.duplicate) | |
117 | new_rule->with_duplicates = 1; | |
118 | else | |
119 | new_rule->with_duplicates = name2i (decode_options, decode_duplicates_map); | |
120 | if (options.decode.combine) | |
121 | new_rule->with_combine = 1; | |
122 | else | |
123 | new_rule->with_combine = name2i (decode_options, decode_combine_map); | |
124 | if (new_rule->type == boolean_rule) | |
125 | { | |
126 | char *chp = decode_options; | |
127 | while (*chp != '\0') | |
128 | { | |
129 | if (isdigit (*chp)) | |
130 | { | |
131 | new_rule->constant = a2i (chp); | |
132 | break; | |
133 | } | |
134 | chp = skip_to_separator (chp, ","); | |
135 | chp = skip_spaces (chp); | |
136 | } | |
137 | } | |
138 | ||
139 | /* First and last */ | |
140 | if (entry->nr_fields > decode_first_field | |
141 | && strlen (entry->field[decode_first_field]) > 0) | |
142 | { | |
143 | new_rule->first = target_a2i (options.hi_bit_nr, | |
144 | entry->field[decode_first_field]); | |
145 | if (new_rule->first < 0 || new_rule->first >= options.insn_bit_size) | |
146 | error (new_rule->line, "First field out of range\n"); | |
147 | } | |
148 | else | |
149 | new_rule->first = 0; | |
150 | if (entry->nr_fields > decode_last_field | |
151 | && strlen (entry->field[decode_last_field]) > 0) | |
152 | { | |
153 | new_rule->last = target_a2i (options.hi_bit_nr, | |
154 | entry->field[decode_last_field]); | |
155 | if (new_rule->last < 0 || new_rule->last >= options.insn_bit_size) | |
156 | error (new_rule->line, "Last field out of range\n"); | |
157 | } | |
158 | else | |
159 | new_rule->last = options.insn_bit_size - 1; | |
160 | if (new_rule->first > new_rule->last) | |
161 | error (new_rule->line, "First must preceed last\n"); | |
162 | ||
163 | /* force first/last, with default values based on first/last */ | |
164 | if (entry->nr_fields > decode_force_first_field | |
165 | && strlen (entry->field[decode_force_first_field]) > 0) | |
166 | { | |
167 | new_rule->force_first = target_a2i (options.hi_bit_nr, | |
168 | entry->field[decode_force_first_field]); | |
169 | if (new_rule->force_first < new_rule->first | |
170 | || new_rule->force_first > new_rule->last + 1) | |
171 | error (new_rule->line, "Force first out of range\n"); | |
172 | } | |
173 | else | |
174 | new_rule->force_first = new_rule->last + 1; | |
175 | if (entry->nr_fields > decode_force_last_field | |
176 | && strlen (entry->field[decode_force_last_field]) > 0) | |
177 | { | |
178 | new_rule->force_last = target_a2i (options.hi_bit_nr, | |
179 | entry->field[decode_force_last_field]); | |
180 | if (new_rule->force_last > new_rule->last | |
181 | || new_rule->force_last < new_rule->first - 1) | |
182 | error (new_rule->line, "Force-last out of range\n"); | |
183 | } | |
184 | else | |
185 | new_rule->force_last = new_rule->first - 1; | |
186 | ||
187 | /* fields to be treated as constant */ | |
188 | if (entry->nr_fields > decode_constant_field_names_field) | |
189 | filter_parse (&new_rule->constant_field_names, | |
190 | entry->field[decode_constant_field_names_field]); | |
191 | ||
192 | /* applicable word nr */ | |
193 | if (entry->nr_fields > decode_word_nr_field) | |
194 | new_rule->word_nr = a2i (entry->field[decode_word_nr_field]); | |
195 | ||
196 | /* required instruction format names */ | |
197 | if (entry->nr_fields > decode_format_names_field) | |
198 | filter_parse (&new_rule->format_names, | |
199 | entry->field[decode_format_names_field]); | |
200 | ||
201 | /* required processor models */ | |
202 | if (entry->nr_fields > decode_model_names_field) | |
203 | filter_parse (&new_rule->model_names, | |
204 | entry->field[decode_model_names_field]); | |
205 | ||
206 | /* required paths */ | |
207 | if (entry->nr_fields > decode_paths_field | |
208 | && strlen (entry->field[decode_paths_field]) > 0) | |
209 | { | |
210 | decode_path_list **last = &new_rule->paths; | |
211 | char *chp = entry->field[decode_paths_field]; | |
212 | do | |
213 | { | |
214 | (*last) = ZALLOC (decode_path_list); | |
215 | /* extra root/zero entry */ | |
216 | (*last)->path = ZALLOC (decode_path); | |
217 | do | |
218 | { | |
219 | decode_path *entry = ZALLOC (decode_path); | |
220 | entry->opcode_nr = a2i (chp); | |
221 | entry->parent = (*last)->path; | |
222 | (*last)->path = entry; | |
223 | chp = skip_digits (chp); | |
224 | chp = skip_spaces (chp); | |
225 | } | |
226 | while (*chp == '.'); | |
227 | last = &(*last)->next; | |
228 | } | |
229 | while (*chp == ','); | |
230 | if (*chp != '\0') | |
231 | error (entry->line, "Invalid path field\n"); | |
232 | } | |
233 | ||
234 | /* collect up the list of optional special conditions applicable | |
235 | to the rule */ | |
236 | { | |
237 | int field_nr = nr_decode_fields; | |
238 | while (entry->nr_fields > field_nr) | |
239 | { | |
240 | decode_cond *cond = ZALLOC (decode_cond); | |
241 | decode_cond **last; | |
242 | if (entry->nr_fields > field_nr + decode_cond_mask_field) | |
243 | set_bits (cond->mask, a2i (entry->field[field_nr + decode_cond_mask_field])); | |
244 | if (entry->nr_fields > field_nr + decode_cond_value_field) | |
245 | { | |
246 | if (entry->field[field_nr + decode_cond_value_field][0] == '!') | |
247 | { | |
248 | cond->is_equal = 0; | |
249 | set_bits (cond->value, a2i (entry->field[field_nr + decode_cond_value_field] + 1)); | |
250 | } | |
251 | else | |
252 | { | |
253 | cond->is_equal = 1; | |
254 | set_bits (cond->value, a2i (entry->field[field_nr + decode_cond_value_field])); | |
255 | } | |
256 | } | |
257 | if (entry->nr_fields > field_nr + decode_cond_word_nr_field) | |
258 | cond->word_nr = a2i (entry->field[field_nr + decode_cond_word_nr_field]); | |
259 | field_nr += nr_decode_cond_fields; | |
260 | /* insert it */ | |
261 | last = &new_rule->conditions; | |
262 | while (*last != NULL) | |
263 | last = &(*last)->next; | |
264 | *last = cond; | |
265 | } | |
266 | } | |
267 | *curr_rule = new_rule; | |
268 | curr_rule = &new_rule->next; | |
269 | } | |
270 | return table; | |
271 | } | |
272 | ||
273 | ||
274 | int | |
275 | decode_table_max_word_nr (decode_table *entry) | |
276 | { | |
277 | int max_word_nr = 0; | |
278 | while (entry != NULL) | |
279 | { | |
280 | decode_cond *cond; | |
281 | if (entry->word_nr > max_word_nr) | |
282 | max_word_nr = entry->word_nr; | |
283 | for (cond = entry->conditions; cond != NULL; cond = cond->next) | |
284 | { | |
285 | if (cond->word_nr > max_word_nr) | |
286 | max_word_nr = cond->word_nr; | |
287 | } | |
288 | entry = entry->next; | |
289 | } | |
290 | return max_word_nr; | |
291 | } | |
292 | ||
293 | ||
294 | ||
295 | static void | |
296 | dump_decode_cond (lf *file, | |
297 | char *prefix, | |
298 | decode_cond *cond, | |
299 | char *suffix) | |
300 | { | |
301 | lf_printf (file, "%s(decode_cond *) 0x%lx", prefix, (long) cond); | |
302 | if (cond != NULL) | |
303 | { | |
304 | lf_indent (file, +1); | |
305 | lf_printf (file, "\n(word_nr %d)", cond->word_nr); | |
306 | lf_printf (file, "\n(mask 0x%lx)", (long) cond->mask); | |
307 | lf_printf (file, "\n(value 0x%lx)", (long) cond->value); | |
308 | lf_printf (file, "\n(is_equal 0x%lx)", (long) cond->is_equal); | |
309 | lf_printf (file, "\n(next (decode_cond *) 0%lx)", (long) cond->next); | |
310 | lf_indent (file, -1); | |
311 | } | |
312 | lf_printf (file, "%s", suffix); | |
313 | } | |
314 | ||
315 | ||
316 | static void | |
317 | dump_decode_conds (lf *file, | |
318 | char *prefix, | |
319 | decode_cond *cond, | |
320 | char *suffix) | |
321 | { | |
322 | lf_printf (file, "%s(decode_cond *) 0x%lx", prefix, (long) cond); | |
323 | while (cond != NULL) | |
324 | { | |
325 | dump_decode_cond (file, "\n(", cond, ")"); | |
326 | cond = cond->next; | |
327 | } | |
328 | lf_printf (file, "%s", suffix); | |
329 | } | |
330 | ||
331 | ||
332 | void | |
333 | dump_decode_rule (lf *file, | |
334 | char *prefix, | |
335 | decode_table *rule, | |
336 | char *suffix) | |
337 | { | |
338 | lf_printf (file, "%s(decode_table *) 0x%lx", prefix, (long) rule); | |
339 | if (rule != NULL) | |
340 | { | |
341 | lf_indent (file, +1); | |
342 | dump_line_ref (file, "\n(line ", rule->line, ")"); | |
343 | lf_printf (file, "\n(type %s)", i2name(rule->type, decode_type_map)); | |
344 | lf_printf (file, "\n(gen %s)", i2name(rule->gen, decode_gen_map)); | |
345 | lf_printf (file, "\n(first %d)", rule->first); | |
346 | lf_printf (file, "\n(last %d)", rule->last); | |
347 | lf_printf (file, "\n(force_first %d)", rule->force_first); | |
348 | lf_printf (file, "\n(force_last %d)", rule->force_last); | |
349 | dump_filter (file, "\n(constant_field_names \"", rule->constant_field_names, "\")"); | |
350 | lf_printf (file, "\n(constant 0x%x)", rule->constant); | |
351 | lf_printf (file, "\n(word_nr %d)", rule->word_nr); | |
352 | lf_printf (file, "\n(with_zero_reserved %d)", rule->with_zero_reserved); | |
353 | lf_printf (file, "\n(with_duplicates %d)", rule->with_duplicates); | |
354 | lf_printf (file, "\n(with_combine %d)", rule->with_combine); | |
355 | dump_filter (file, "\n(format_names \"", rule->format_names, "\")"); | |
356 | dump_filter (file, "\n(model_names \"", rule->model_names, "\")"); | |
357 | dump_decode_conds (file, "\n(conditions ", rule->conditions, ")"); | |
358 | lf_printf (file, "\n(next 0x%lx)", (long) rule->next); | |
359 | lf_indent (file, -1); | |
360 | } | |
361 | lf_printf (file, "%s", suffix); | |
362 | } | |
363 | ||
364 | ||
365 | #ifdef MAIN | |
366 | ||
367 | static void | |
368 | dump_decode_rules (lf *file, | |
369 | char *prefix, | |
370 | decode_table *rule, | |
371 | char *suffix) | |
372 | { | |
373 | lf_printf (file, "%s", prefix); | |
374 | while (rule != NULL) | |
375 | { | |
376 | lf_indent (file, +1); | |
377 | dump_decode_rule (file, "\n(", rule, ")"); | |
378 | lf_indent (file, -1); | |
379 | rule = rule->next; | |
380 | } | |
381 | lf_printf (file, "%s", suffix); | |
382 | } | |
383 | ||
384 | igen_options options; | |
385 | ||
386 | int | |
387 | main(int argc, char **argv) | |
388 | { | |
389 | lf *l; | |
390 | decode_table *rules; | |
391 | ||
392 | INIT_OPTIONS (options); | |
393 | ||
394 | if (argc != 3) | |
395 | error (NULL, "Usage: decode <decode-file> <hi-bit-nr>\n"); | |
396 | ||
397 | options.hi_bit_nr = a2i (argv[2]); | |
398 | rules = load_decode_table (argv[1]); | |
399 | l = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "tmp-ld-insn"); | |
400 | dump_decode_rules (l, "(rules ", rules, ")\n"); | |
401 | ||
402 | return 0; | |
403 | } | |
404 | #endif |