Commit | Line | Data |
---|---|---|
feaee4bd AC |
1 | /* The IGEN simulator generator for GDB, the GNU Debugger. |
2 | ||
3 | Copyright 2002 Free Software Foundation, Inc. | |
4 | ||
5 | Contributed by Andrew Cagney. | |
6 | ||
7 | This file is part of GDB. | |
8 | ||
9 | This program is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 2 of the License, or | |
12 | (at your option) any later version. | |
13 | ||
14 | This program is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with this program; if not, write to the Free Software | |
21 | Foundation, Inc., 59 Temple Place - Suite 330, | |
22 | Boston, MA 02111-1307, USA. */ | |
23 | ||
c906108c SS |
24 | |
25 | #include "misc.h" | |
26 | #include "lf.h" | |
27 | #include "table.h" | |
28 | #include "filter.h" | |
29 | #include "igen.h" | |
30 | ||
31 | #include "ld-insn.h" | |
32 | #include "ld-decode.h" | |
33 | ||
34 | #include "gen.h" | |
35 | ||
36 | #include "gen-idecode.h" | |
37 | #include "gen-icache.h" | |
38 | #include "gen-semantics.h" | |
39 | ||
40 | ||
41 | ||
42 | static void | |
4e0bf4c4 | 43 | lf_print_opcodes (lf *file, gen_entry *table) |
c906108c | 44 | { |
4e0bf4c4 | 45 | if (table !=NULL) |
c906108c SS |
46 | { |
47 | while (1) | |
48 | { | |
49 | ASSERT (table->opcode != NULL); | |
50 | lf_printf (file, "_%d_%d", | |
4e0bf4c4 AC |
51 | table->opcode->first, table->opcode->last); |
52 | if (table->parent == NULL) | |
53 | break; | |
c906108c SS |
54 | lf_printf (file, "__%d", table->opcode_nr); |
55 | table = table->parent; | |
56 | } | |
57 | } | |
58 | } | |
59 | ||
60 | ||
61 | ||
62 | ||
63 | static void | |
64 | print_idecode_ifetch (lf *file, | |
65 | int previous_nr_prefetched_words, | |
66 | int current_nr_prefetched_words) | |
67 | { | |
68 | int word_nr; | |
69 | for (word_nr = previous_nr_prefetched_words; | |
4e0bf4c4 | 70 | word_nr < current_nr_prefetched_words; word_nr++) |
c906108c | 71 | { |
4e0bf4c4 AC |
72 | lf_printf (file, |
73 | "instruction_word instruction_%d = IMEM%d_IMMED (cia, %d);\n", | |
c906108c | 74 | word_nr, options.insn_bit_size, word_nr); |
4e0bf4c4 | 75 | |
c906108c SS |
76 | } |
77 | } | |
78 | ||
79 | ||
80 | ||
81 | /****************************************************************/ | |
82 | ||
83 | ||
84 | static void | |
4e0bf4c4 | 85 | lf_print_table_name (lf *file, gen_entry *table) |
c906108c SS |
86 | { |
87 | lf_printf (file, "idecode_table"); | |
88 | lf_print_opcodes (file, table); | |
89 | } | |
90 | ||
91 | ||
92 | ||
93 | static void | |
4e0bf4c4 | 94 | print_idecode_table (lf *file, gen_entry *entry, const char *result) |
c906108c SS |
95 | { |
96 | lf_printf (file, "/* prime the search */\n"); | |
97 | lf_printf (file, "idecode_table_entry *table = "); | |
98 | lf_print_table_name (file, entry); | |
99 | lf_printf (file, ";\n"); | |
100 | lf_printf (file, "int opcode = EXTRACTED%d (instruction, %d, %d);\n", | |
101 | options.insn_bit_size, | |
102 | i2target (options.hi_bit_nr, entry->opcode->first), | |
103 | i2target (options.hi_bit_nr, entry->opcode->last)); | |
104 | lf_printf (file, "idecode_table_entry *table_entry = table + opcode;\n"); | |
4e0bf4c4 | 105 | |
c906108c SS |
106 | lf_printf (file, "\n"); |
107 | lf_printf (file, "/* iterate until a leaf */\n"); | |
108 | lf_printf (file, "while (1) {\n"); | |
109 | lf_printf (file, " signed shift = table_entry->shift;\n"); | |
110 | lf_printf (file, "if (shift == function_entry) break;\n"); | |
111 | lf_printf (file, " if (shift >= 0) {\n"); | |
112 | lf_printf (file, " table = ((idecode_table_entry*)\n"); | |
113 | lf_printf (file, " table_entry->function_or_table);\n"); | |
114 | lf_printf (file, " opcode = ((instruction & table_entry->mask)\n"); | |
115 | lf_printf (file, " >> shift);\n"); | |
116 | lf_printf (file, " table_entry = table + opcode;\n"); | |
117 | lf_printf (file, " }\n"); | |
118 | lf_printf (file, " else {\n"); | |
119 | lf_printf (file, " /* must be a boolean */\n"); | |
120 | lf_printf (file, " ASSERT(table_entry->shift == boolean_entry);\n"); | |
121 | lf_printf (file, " opcode = ((instruction & table_entry->mask)\n"); | |
122 | lf_printf (file, " != table_entry->value);\n"); | |
123 | lf_printf (file, " table = ((idecode_table_entry*)\n"); | |
124 | lf_printf (file, " table_entry->function_or_table);\n"); | |
125 | lf_printf (file, " table_entry = table + opcode;\n"); | |
126 | lf_printf (file, " }\n"); | |
127 | lf_printf (file, "}\n"); | |
4e0bf4c4 | 128 | |
c906108c SS |
129 | lf_printf (file, "\n"); |
130 | lf_printf (file, "/* call the leaf code */\n"); | |
131 | if (options.gen.code == generate_jumps) | |
132 | { | |
133 | lf_printf (file, "goto *table_entry->function_or_table;\n"); | |
134 | } | |
135 | else | |
136 | { | |
137 | lf_printf (file, "%s ", result); | |
138 | if (options.gen.icache) | |
139 | { | |
4e0bf4c4 AC |
140 | lf_printf (file, |
141 | "(((idecode_icache*)table_entry->function_or_table)\n"); | |
c906108c SS |
142 | lf_printf (file, " ("); |
143 | print_icache_function_actual (file, 1); | |
144 | lf_printf (file, "));\n"); | |
145 | } | |
146 | else | |
147 | { | |
4e0bf4c4 AC |
148 | lf_printf (file, |
149 | "((idecode_semantic*)table_entry->function_or_table)\n"); | |
c906108c SS |
150 | lf_printf (file, " ("); |
151 | print_semantic_function_actual (file, 1); | |
152 | lf_printf (file, ");\n"); | |
153 | } | |
154 | } | |
155 | } | |
156 | ||
157 | ||
158 | static void | |
4e0bf4c4 | 159 | print_idecode_table_start (lf *file, gen_entry *table, int depth, void *data) |
c906108c SS |
160 | { |
161 | ASSERT (depth == 0); | |
162 | /* start of the table */ | |
163 | if (table->opcode_rule->gen == array_gen) | |
164 | { | |
165 | lf_printf (file, "\n"); | |
166 | lf_printf (file, "static idecode_table_entry "); | |
167 | lf_print_table_name (file, table); | |
168 | lf_printf (file, "[] = {\n"); | |
169 | } | |
170 | } | |
171 | ||
172 | static void | |
4e0bf4c4 | 173 | print_idecode_table_leaf (lf *file, gen_entry *entry, int depth, void *data) |
c906108c SS |
174 | { |
175 | gen_entry *master_entry; | |
176 | ASSERT (entry->parent != NULL); | |
177 | ASSERT (depth == 0); | |
178 | if (entry->combined_parent == NULL) | |
179 | master_entry = entry; | |
180 | else | |
181 | master_entry = entry->combined_parent; | |
182 | ||
183 | /* add an entry to the table */ | |
184 | if (entry->parent->opcode_rule->gen == array_gen) | |
185 | { | |
186 | lf_printf (file, " /*%d*/ { ", entry->opcode_nr); | |
187 | if (entry->opcode == NULL) | |
188 | { | |
189 | ASSERT (entry->nr_insns == 1); | |
190 | /* table leaf entry */ | |
191 | lf_printf (file, "function_entry, 0, 0, "); | |
192 | if (options.gen.code == generate_jumps) | |
193 | { | |
194 | lf_printf (file, "&&"); | |
195 | } | |
196 | print_function_name (file, | |
197 | entry->insns->insn->name, | |
198 | entry->insns->insn->format_name, | |
199 | NULL, | |
200 | master_entry->expanded_bits, | |
201 | (options.gen.icache | |
202 | ? function_name_prefix_icache | |
203 | : function_name_prefix_semantics)); | |
204 | } | |
205 | else if (entry->opcode_rule->gen == switch_gen | |
206 | || entry->opcode_rule->gen == goto_switch_gen | |
207 | || entry->opcode_rule->gen == padded_switch_gen) | |
208 | { | |
209 | /* table calling switch statement */ | |
210 | lf_printf (file, "function_entry, 0, 0, "); | |
211 | if (options.gen.code == generate_jumps) | |
212 | { | |
213 | lf_printf (file, "&&"); | |
214 | } | |
215 | lf_print_table_name (file, entry); | |
216 | } | |
217 | else if (entry->opcode->is_boolean) | |
218 | { | |
219 | /* table `calling' boolean table */ | |
220 | lf_printf (file, "boolean_entry, "); | |
221 | lf_printf (file, "MASK32(%d, %d), ", | |
222 | i2target (options.hi_bit_nr, entry->opcode->first), | |
223 | i2target (options.hi_bit_nr, entry->opcode->last)); | |
224 | lf_printf (file, "INSERTED32(%d, %d, %d), ", | |
225 | entry->opcode->boolean_constant, | |
226 | i2target (options.hi_bit_nr, entry->opcode->first), | |
227 | i2target (options.hi_bit_nr, entry->opcode->last)); | |
228 | lf_print_table_name (file, entry); | |
229 | } | |
230 | else | |
231 | { | |
232 | /* table `calling' another table */ | |
4e0bf4c4 AC |
233 | lf_printf (file, "%d, ", |
234 | options.insn_bit_size - entry->opcode->last - 1); | |
235 | lf_printf (file, "MASK%d(%d,%d), ", options.insn_bit_size, | |
c906108c SS |
236 | i2target (options.hi_bit_nr, entry->opcode->first), |
237 | i2target (options.hi_bit_nr, entry->opcode->last)); | |
238 | lf_printf (file, "0, "); | |
239 | lf_print_table_name (file, entry); | |
240 | } | |
241 | lf_printf (file, " },\n"); | |
242 | } | |
243 | } | |
244 | ||
245 | static void | |
4e0bf4c4 | 246 | print_idecode_table_end (lf *file, gen_entry *table, int depth, void *data) |
c906108c SS |
247 | { |
248 | ASSERT (depth == 0); | |
4e0bf4c4 AC |
249 | if (table->opcode_rule->gen == array_gen) |
250 | { | |
251 | lf_printf (file, "};\n"); | |
252 | } | |
c906108c SS |
253 | } |
254 | ||
255 | /****************************************************************/ | |
256 | ||
257 | ||
258 | static void | |
4e0bf4c4 | 259 | print_goto_switch_name (lf *file, gen_entry *entry) |
c906108c SS |
260 | { |
261 | lf_printf (file, "case_"); | |
262 | if (entry->opcode == NULL) | |
263 | { | |
264 | print_function_name (file, | |
265 | entry->insns->insn->name, | |
266 | entry->insns->insn->format_name, | |
267 | NULL, | |
268 | entry->expanded_bits, | |
269 | (options.gen.icache | |
270 | ? function_name_prefix_icache | |
271 | : function_name_prefix_semantics)); | |
272 | } | |
273 | else | |
274 | { | |
4e0bf4c4 | 275 | lf_print_table_name (file, entry); |
c906108c SS |
276 | } |
277 | } | |
278 | ||
279 | static void | |
280 | print_goto_switch_table_leaf (lf *file, | |
4e0bf4c4 | 281 | gen_entry *entry, int depth, void *data) |
c906108c SS |
282 | { |
283 | ASSERT (entry->parent != NULL); | |
284 | ASSERT (depth == 0); | |
285 | ASSERT (entry->parent->opcode_rule->gen == goto_switch_gen); | |
286 | ASSERT (entry->parent->opcode); | |
4e0bf4c4 | 287 | |
c906108c SS |
288 | lf_printf (file, "/* %d */ &&", entry->opcode_nr); |
289 | if (entry->combined_parent != NULL) | |
290 | print_goto_switch_name (file, entry->combined_parent); | |
291 | else | |
292 | print_goto_switch_name (file, entry); | |
293 | lf_printf (file, ",\n"); | |
294 | } | |
295 | ||
296 | static void | |
4e0bf4c4 | 297 | print_goto_switch_break (lf *file, gen_entry *entry) |
c906108c SS |
298 | { |
299 | lf_printf (file, "goto break_"); | |
300 | lf_print_table_name (file, entry->parent); | |
301 | lf_printf (file, ";\n"); | |
302 | } | |
303 | ||
304 | ||
305 | static void | |
4e0bf4c4 | 306 | print_goto_switch_table (lf *file, gen_entry *table) |
c906108c SS |
307 | { |
308 | lf_printf (file, "const static void *"); | |
309 | lf_print_table_name (file, table); | |
310 | lf_printf (file, "[] = {\n"); | |
311 | lf_indent (file, +2); | |
4e0bf4c4 AC |
312 | gen_entry_traverse_tree (file, table, 0, NULL /*start */ , |
313 | print_goto_switch_table_leaf, NULL /*end */ , | |
314 | NULL /*data */ ); | |
c906108c SS |
315 | lf_indent (file, -2); |
316 | lf_printf (file, "};\n"); | |
317 | } | |
318 | ||
319 | ||
4e0bf4c4 | 320 | void print_idecode_switch (lf *file, gen_entry *table, const char *result); |
c906108c SS |
321 | |
322 | static void | |
4e0bf4c4 | 323 | print_idecode_switch_start (lf *file, gen_entry *table, int depth, void *data) |
c906108c SS |
324 | { |
325 | /* const char *result = data; */ | |
326 | ASSERT (depth == 0); | |
327 | ASSERT (table->opcode_rule->gen == switch_gen | |
328 | || table->opcode_rule->gen == goto_switch_gen | |
329 | || table->opcode_rule->gen == padded_switch_gen); | |
4e0bf4c4 | 330 | |
c906108c SS |
331 | if (table->opcode->is_boolean |
332 | || table->opcode_rule->gen == switch_gen | |
333 | || table->opcode_rule->gen == padded_switch_gen) | |
334 | { | |
335 | lf_printf (file, "switch (EXTRACTED%d (instruction_%d, %d, %d))\n", | |
336 | options.insn_bit_size, | |
337 | table->opcode_rule->word_nr, | |
338 | i2target (options.hi_bit_nr, table->opcode->first), | |
339 | i2target (options.hi_bit_nr, table->opcode->last)); | |
340 | lf_indent (file, +2); | |
341 | lf_printf (file, "{\n"); | |
342 | } | |
343 | else if (table->opcode_rule->gen == goto_switch_gen) | |
344 | { | |
345 | if (table->parent != NULL | |
346 | && (table->parent->opcode_rule->gen == switch_gen | |
347 | || table->parent->opcode_rule->gen == goto_switch_gen | |
348 | || table->parent->opcode_rule->gen == padded_switch_gen)) | |
349 | { | |
350 | lf_printf (file, "{\n"); | |
351 | lf_indent (file, +2); | |
352 | } | |
353 | print_goto_switch_table (file, table); | |
354 | lf_printf (file, "ASSERT (EXTRACTED%d (instruction_%d, %d, %d)\n", | |
355 | options.insn_bit_size, | |
356 | table->opcode->word_nr, | |
357 | i2target (options.hi_bit_nr, table->opcode->first), | |
358 | i2target (options.hi_bit_nr, table->opcode->last)); | |
359 | lf_printf (file, " < (sizeof ("); | |
360 | lf_print_table_name (file, table); | |
361 | lf_printf (file, ") / sizeof(void*)));\n"); | |
362 | lf_printf (file, "goto *"); | |
363 | lf_print_table_name (file, table); | |
364 | lf_printf (file, "[EXTRACTED%d (instruction_%d, %d, %d)];\n", | |
365 | options.insn_bit_size, | |
366 | table->opcode->word_nr, | |
367 | i2target (options.hi_bit_nr, table->opcode->first), | |
368 | i2target (options.hi_bit_nr, table->opcode->last)); | |
369 | } | |
370 | else | |
371 | { | |
4e0bf4c4 | 372 | ASSERT ("bad switch" == NULL); |
c906108c SS |
373 | } |
374 | } | |
375 | ||
376 | ||
377 | static void | |
4e0bf4c4 | 378 | print_idecode_switch_leaf (lf *file, gen_entry *entry, int depth, void *data) |
c906108c SS |
379 | { |
380 | const char *result = data; | |
381 | ASSERT (entry->parent != NULL); | |
382 | ASSERT (depth == 0); | |
383 | ASSERT (entry->parent->opcode_rule->gen == switch_gen | |
384 | || entry->parent->opcode_rule->gen == goto_switch_gen | |
385 | || entry->parent->opcode_rule->gen == padded_switch_gen); | |
386 | ASSERT (entry->parent->opcode); | |
4e0bf4c4 | 387 | |
c906108c SS |
388 | /* skip over any instructions combined into another entry */ |
389 | if (entry->combined_parent != NULL) | |
390 | return; | |
391 | ||
4e0bf4c4 | 392 | if (entry->parent->opcode->is_boolean && entry->opcode_nr == 0) |
c906108c SS |
393 | { |
394 | /* case: boolean false target */ | |
395 | lf_printf (file, "case %d:\n", entry->parent->opcode->boolean_constant); | |
396 | } | |
4e0bf4c4 | 397 | else if (entry->parent->opcode->is_boolean && entry->opcode_nr != 0) |
c906108c SS |
398 | { |
399 | /* case: boolean true case */ | |
400 | lf_printf (file, "default:\n"); | |
401 | } | |
402 | else if (entry->parent->opcode_rule->gen == switch_gen | |
403 | || entry->parent->opcode_rule->gen == padded_switch_gen) | |
404 | { | |
405 | /* case: <opcode-nr> - switch */ | |
406 | gen_entry *cob; | |
407 | for (cob = entry; cob != NULL; cob = cob->combined_next) | |
408 | lf_printf (file, "case %d:\n", cob->opcode_nr); | |
409 | } | |
410 | else if (entry->parent->opcode_rule->gen == goto_switch_gen) | |
411 | { | |
412 | /* case: <opcode-nr> - goto-switch */ | |
413 | print_goto_switch_name (file, entry); | |
414 | lf_printf (file, ":\n"); | |
415 | } | |
416 | else | |
417 | { | |
418 | ERROR ("bad switch"); | |
419 | } | |
420 | lf_printf (file, " {\n"); | |
421 | lf_indent (file, +4); | |
422 | { | |
423 | if (entry->opcode == NULL) | |
424 | { | |
425 | /* switch calling leaf */ | |
426 | ASSERT (entry->nr_insns == 1); | |
427 | print_idecode_ifetch (file, entry->nr_prefetched_words, | |
428 | entry->insns->semantic->nr_prefetched_words); | |
429 | switch (options.gen.code) | |
430 | { | |
431 | case generate_jumps: | |
432 | lf_printf (file, "goto "); | |
433 | break; | |
434 | case generate_calls: | |
435 | lf_printf (file, "%s", result); | |
436 | break; | |
437 | } | |
438 | print_function_name (file, | |
439 | entry->insns->insn->name, | |
440 | entry->insns->insn->format_name, | |
441 | NULL, | |
442 | entry->expanded_bits, | |
443 | (options.gen.icache | |
444 | ? function_name_prefix_icache | |
445 | : function_name_prefix_semantics)); | |
446 | if (options.gen.code == generate_calls) | |
447 | { | |
448 | lf_printf (file, " ("); | |
4e0bf4c4 AC |
449 | print_semantic_function_actual (file, |
450 | entry->insns->semantic-> | |
451 | nr_prefetched_words); | |
c906108c SS |
452 | lf_printf (file, ")"); |
453 | } | |
454 | lf_printf (file, ";\n"); | |
455 | } | |
456 | else if (entry->opcode_rule->gen == switch_gen | |
457 | || entry->opcode_rule->gen == goto_switch_gen | |
458 | || entry->opcode_rule->gen == padded_switch_gen) | |
459 | { | |
460 | /* switch calling switch */ | |
461 | lf_printf (file, "{\n"); | |
462 | lf_indent (file, +2); | |
463 | print_idecode_ifetch (file, entry->parent->nr_prefetched_words, | |
464 | entry->nr_prefetched_words); | |
465 | print_idecode_switch (file, entry, result); | |
466 | lf_indent (file, -2); | |
467 | lf_printf (file, "}\n"); | |
468 | } | |
469 | else | |
470 | { | |
471 | /* switch looking up a table */ | |
472 | lf_printf (file, "{\n"); | |
473 | lf_indent (file, +2); | |
474 | print_idecode_ifetch (file, entry->parent->nr_prefetched_words, | |
475 | entry->nr_prefetched_words); | |
476 | print_idecode_table (file, entry, result); | |
477 | lf_indent (file, -2); | |
478 | lf_printf (file, "}\n"); | |
479 | } | |
480 | if (entry->parent->opcode->is_boolean | |
481 | || entry->parent->opcode_rule->gen == switch_gen | |
482 | || entry->parent->opcode_rule->gen == padded_switch_gen) | |
483 | { | |
484 | lf_printf (file, "break;\n"); | |
485 | } | |
486 | else if (entry->parent->opcode_rule->gen == goto_switch_gen) | |
487 | { | |
4e0bf4c4 | 488 | print_goto_switch_break (file, entry); |
c906108c SS |
489 | } |
490 | else | |
491 | { | |
492 | ERROR ("bad switch"); | |
493 | } | |
494 | } | |
495 | lf_indent (file, -4); | |
496 | lf_printf (file, " }\n"); | |
497 | } | |
498 | ||
499 | ||
500 | static void | |
4e0bf4c4 | 501 | print_idecode_switch_illegal (lf *file, const char *result) |
c906108c SS |
502 | { |
503 | lf_indent (file, +2); | |
504 | print_idecode_invalid (file, result, invalid_illegal); | |
505 | lf_printf (file, "break;\n"); | |
506 | lf_indent (file, -2); | |
507 | } | |
508 | ||
509 | static void | |
4e0bf4c4 | 510 | print_idecode_switch_end (lf *file, gen_entry *table, int depth, void *data) |
c906108c SS |
511 | { |
512 | const char *result = data; | |
513 | ASSERT (depth == 0); | |
514 | ASSERT (table->opcode_rule->gen == switch_gen | |
515 | || table->opcode_rule->gen == goto_switch_gen | |
516 | || table->opcode_rule->gen == padded_switch_gen); | |
517 | ASSERT (table->opcode); | |
4e0bf4c4 | 518 | |
c906108c SS |
519 | if (table->opcode->is_boolean) |
520 | { | |
521 | lf_printf (file, "}\n"); | |
522 | lf_indent (file, -2); | |
523 | } | |
524 | else if (table->opcode_rule->gen == switch_gen | |
525 | || table->opcode_rule->gen == padded_switch_gen) | |
526 | { | |
527 | lf_printf (file, "default:\n"); | |
528 | lf_indent (file, +2); | |
529 | if (table->nr_entries == table->opcode->nr_opcodes) | |
530 | { | |
4e0bf4c4 AC |
531 | print_sim_engine_abort (file, |
532 | "Internal error - bad switch generated"); | |
c906108c SS |
533 | lf_printf (file, "%sNULL_CIA;\n", result); |
534 | lf_printf (file, "break;\n"); | |
535 | } | |
536 | else | |
537 | { | |
538 | print_idecode_switch_illegal (file, result); | |
539 | } | |
540 | lf_indent (file, -2); | |
541 | lf_printf (file, "}\n"); | |
542 | lf_indent (file, -2); | |
543 | } | |
544 | else if (table->opcode_rule->gen == goto_switch_gen) | |
545 | { | |
546 | lf_printf (file, "illegal_"); | |
547 | lf_print_table_name (file, table); | |
548 | lf_printf (file, ":\n"); | |
549 | print_idecode_invalid (file, result, invalid_illegal); | |
550 | lf_printf (file, "break_"); | |
4e0bf4c4 | 551 | lf_print_table_name (file, table); |
c906108c SS |
552 | lf_printf (file, ":;\n"); |
553 | if (table->parent != NULL | |
554 | && (table->parent->opcode_rule->gen == switch_gen | |
555 | || table->parent->opcode_rule->gen == goto_switch_gen | |
556 | || table->parent->opcode_rule->gen == padded_switch_gen)) | |
557 | { | |
558 | lf_indent (file, -2); | |
559 | lf_printf (file, "}\n"); | |
560 | } | |
561 | } | |
562 | else | |
563 | { | |
564 | ERROR ("bad switch"); | |
565 | } | |
566 | } | |
567 | ||
568 | ||
569 | void | |
4e0bf4c4 | 570 | print_idecode_switch (lf *file, gen_entry *table, const char *result) |
c906108c SS |
571 | { |
572 | gen_entry_traverse_tree (file, table, | |
573 | 0, | |
574 | print_idecode_switch_start, | |
575 | print_idecode_switch_leaf, | |
4e0bf4c4 | 576 | print_idecode_switch_end, (void *) result); |
c906108c SS |
577 | } |
578 | ||
579 | ||
580 | static void | |
581 | print_idecode_switch_function_header (lf *file, | |
582 | gen_entry *table, | |
583 | int is_function_definition, | |
584 | int nr_prefetched_words) | |
585 | { | |
586 | lf_printf (file, "\n"); | |
587 | if (options.gen.code == generate_calls) | |
588 | { | |
589 | lf_printf (file, "static "); | |
590 | if (options.gen.icache) | |
591 | { | |
592 | lf_printf (file, "idecode_semantic *"); | |
593 | } | |
594 | else | |
595 | { | |
596 | lf_printf (file, "unsigned_word"); | |
597 | } | |
598 | if (is_function_definition) | |
599 | { | |
600 | lf_printf (file, "\n"); | |
601 | } | |
602 | else | |
603 | { | |
604 | lf_printf (file, " "); | |
605 | } | |
606 | lf_print_table_name (file, table); | |
607 | lf_printf (file, "\n("); | |
608 | print_icache_function_formal (file, nr_prefetched_words); | |
609 | lf_printf (file, ")"); | |
610 | if (!is_function_definition) | |
611 | { | |
612 | lf_printf (file, ";"); | |
613 | } | |
614 | lf_printf (file, "\n"); | |
615 | } | |
616 | if (options.gen.code == generate_jumps && is_function_definition) | |
617 | { | |
618 | lf_indent (file, -1); | |
619 | lf_print_table_name (file, table); | |
620 | lf_printf (file, ":\n"); | |
621 | lf_indent (file, +1); | |
622 | } | |
623 | } | |
624 | ||
625 | ||
626 | static void | |
4e0bf4c4 | 627 | idecode_declare_if_switch (lf *file, gen_entry *table, int depth, void *data) |
c906108c | 628 | { |
4e0bf4c4 | 629 | if ((table->opcode_rule->gen == switch_gen || table->opcode_rule->gen == goto_switch_gen || table->opcode_rule->gen == padded_switch_gen) &&table->parent != NULL /* don't declare the top one yet */ |
c906108c SS |
630 | && table->parent->opcode_rule->gen == array_gen) |
631 | { | |
632 | print_idecode_switch_function_header (file, | |
633 | table, | |
4e0bf4c4 | 634 | 0 /*isnt function definition */ , |
c906108c SS |
635 | 0); |
636 | } | |
637 | } | |
638 | ||
639 | ||
640 | static void | |
4e0bf4c4 | 641 | idecode_expand_if_switch (lf *file, gen_entry *table, int depth, void *data) |
c906108c | 642 | { |
4e0bf4c4 | 643 | if ((table->opcode_rule->gen == switch_gen || table->opcode_rule->gen == goto_switch_gen || table->opcode_rule->gen == padded_switch_gen) &&table->parent != NULL /* don't expand the top one yet */ |
c906108c SS |
644 | && table->parent->opcode_rule->gen == array_gen) |
645 | { | |
4e0bf4c4 AC |
646 | print_idecode_switch_function_header (file, |
647 | table, | |
648 | 1 /*is function definition */ , | |
649 | 0); | |
c906108c SS |
650 | if (options.gen.code == generate_calls) |
651 | { | |
652 | lf_printf (file, "{\n"); | |
653 | lf_indent (file, +2); | |
654 | } | |
4e0bf4c4 | 655 | print_idecode_switch (file, table, "return"); |
c906108c SS |
656 | if (options.gen.code == generate_calls) |
657 | { | |
658 | lf_indent (file, -2); | |
659 | lf_printf (file, "}\n"); | |
660 | } | |
661 | } | |
662 | } | |
663 | ||
664 | ||
665 | /****************************************************************/ | |
666 | ||
667 | ||
668 | void | |
4e0bf4c4 | 669 | print_idecode_lookups (lf *file, gen_entry *table, cache_entry *cache_rules) |
c906108c SS |
670 | { |
671 | int depth; | |
4e0bf4c4 | 672 | |
c906108c | 673 | /* output switch function declarations where needed by tables */ |
4e0bf4c4 AC |
674 | gen_entry_traverse_tree (file, table, 1, idecode_declare_if_switch, /* START */ |
675 | NULL, NULL, NULL); | |
676 | ||
c906108c | 677 | /* output tables where needed */ |
4e0bf4c4 | 678 | for (depth = gen_entry_depth (table); depth > 0; depth--) |
c906108c SS |
679 | { |
680 | gen_entry_traverse_tree (file, table, | |
4e0bf4c4 | 681 | 1 - depth, |
c906108c SS |
682 | print_idecode_table_start, |
683 | print_idecode_table_leaf, | |
4e0bf4c4 | 684 | print_idecode_table_end, NULL); |
c906108c | 685 | } |
4e0bf4c4 | 686 | |
c906108c | 687 | /* output switch functions where needed */ |
4e0bf4c4 AC |
688 | gen_entry_traverse_tree (file, table, 1, idecode_expand_if_switch, /* START */ |
689 | NULL, NULL, NULL); | |
c906108c SS |
690 | } |
691 | ||
692 | ||
693 | void | |
4e0bf4c4 | 694 | print_idecode_body (lf *file, gen_entry *table, const char *result) |
c906108c SS |
695 | { |
696 | if (table->opcode_rule->gen == switch_gen | |
697 | || table->opcode_rule->gen == goto_switch_gen | |
698 | || table->opcode_rule->gen == padded_switch_gen) | |
699 | { | |
700 | print_idecode_switch (file, table, result); | |
701 | } | |
702 | else | |
703 | { | |
704 | print_idecode_table (file, table, result); | |
705 | } | |
706 | } | |
707 | ||
708 | ||
709 | /****************************************************************/ | |
710 | ||
711 | #if 0 | |
712 | static void | |
4e0bf4c4 | 713 | print_jump (lf *file, int is_tail) |
c906108c SS |
714 | { |
715 | if (is_tail) | |
716 | { | |
717 | lf_putstr (file, "if (keep_running != NULL && !*keep_running)\n"); | |
718 | lf_putstr (file, " cpu_halt(cpu, nia, was_continuing, 0/*na*/);\n"); | |
719 | } | |
4e0bf4c4 | 720 | |
c906108c SS |
721 | if (!options.generate_smp) |
722 | { | |
723 | lf_putstr (file, "if (WITH_EVENTS) {\n"); | |
724 | lf_putstr (file, " if (event_queue_tick(events)) {\n"); | |
725 | lf_putstr (file, " cpu_set_program_counter(cpu, nia);\n"); | |
726 | lf_putstr (file, " event_queue_process(events);\n"); | |
727 | lf_putstr (file, " nia = cpu_get_program_counter(cpu);\n"); | |
728 | lf_putstr (file, " }\n"); | |
729 | lf_putstr (file, "}\n"); | |
730 | } | |
4e0bf4c4 | 731 | |
c906108c SS |
732 | if (options.generate_smp) |
733 | { | |
734 | if (is_tail) | |
735 | { | |
736 | lf_putstr (file, "cpu_set_program_counter(cpu, nia);\n"); | |
737 | } | |
738 | lf_putstr (file, "if (WITH_EVENTS) {\n"); | |
739 | lf_putstr (file, " current_cpu += 1;\n"); | |
740 | lf_putstr (file, " if (current_cpu >= nr_cpus) {\n"); | |
741 | lf_putstr (file, " if (event_queue_tick(events)) {\n"); | |
742 | lf_putstr (file, " event_queue_process(events);\n"); | |
743 | lf_putstr (file, " }\n"); | |
744 | lf_putstr (file, " current_cpu = 0;\n"); | |
745 | lf_putstr (file, " }\n"); | |
746 | lf_putstr (file, "}\n"); | |
747 | lf_putstr (file, "else {\n"); | |
748 | lf_putstr (file, " current_cpu = (current_cpu + 1) % nr_cpus;\n"); | |
749 | lf_putstr (file, "}\n"); | |
750 | lf_putstr (file, "cpu = cpus[current_cpu];\n"); | |
751 | lf_putstr (file, "nia = cpu_get_program_counter(cpu);\n"); | |
752 | } | |
4e0bf4c4 | 753 | |
c906108c SS |
754 | if (options.gen.icache) |
755 | { | |
756 | lf_putstr (file, "cache_entry = cpu_icache_entry(cpu, nia);\n"); | |
757 | lf_putstr (file, "if (cache_entry->address == nia) {\n"); | |
758 | lf_putstr (file, " /* cache hit */\n"); | |
759 | lf_putstr (file, " goto *cache_entry->semantic;\n"); | |
760 | lf_putstr (file, "}\n"); | |
761 | if (is_tail) | |
762 | { | |
763 | lf_putstr (file, "goto cache_miss;\n"); | |
764 | } | |
765 | } | |
766 | ||
767 | if (!options.gen.icache && is_tail) | |
768 | { | |
769 | lf_printf (file, "goto idecode;\n"); | |
770 | } | |
4e0bf4c4 | 771 | |
c906108c SS |
772 | } |
773 | #endif | |
774 | ||
775 | ||
776 | ||
777 | #if 0 | |
778 | static void | |
779 | print_jump_insn (lf *file, | |
4e0bf4c4 AC |
780 | insn_entry * instruction, |
781 | insn_bits * expanded_bits, | |
782 | opcode_field *opcodes, cache_entry *cache_rules) | |
c906108c | 783 | { |
4e0bf4c4 | 784 | |
c906108c SS |
785 | /* what we are for the moment */ |
786 | lf_printf (file, "\n"); | |
787 | print_my_defines (file, expanded_bits, instruction->name); | |
4e0bf4c4 | 788 | |
c906108c SS |
789 | /* output the icache entry */ |
790 | if (options.gen.icache) | |
791 | { | |
792 | lf_printf (file, "\n"); | |
793 | lf_indent (file, -1); | |
794 | print_function_name (file, | |
795 | instruction->name, | |
4e0bf4c4 | 796 | expanded_bits, function_name_prefix_icache); |
c906108c SS |
797 | lf_printf (file, ":\n"); |
798 | lf_indent (file, +1); | |
799 | lf_printf (file, "{\n"); | |
800 | lf_indent (file, +2); | |
801 | lf_putstr (file, "const unsigned_word cia = nia;\n"); | |
4e0bf4c4 | 802 | print_itrace (file, instruction, 1 /*putting-value-in-cache */ ); |
c906108c SS |
803 | print_idecode_validate (file, instruction, opcodes); |
804 | lf_printf (file, "\n"); | |
805 | lf_printf (file, "{\n"); | |
806 | lf_indent (file, +2); | |
4e0bf4c4 | 807 | print_icache_body (file, instruction, expanded_bits, cache_rules, 0, /*use_defines */ |
c906108c SS |
808 | put_values_in_icache); |
809 | lf_printf (file, "cache_entry->address = nia;\n"); | |
810 | lf_printf (file, "cache_entry->semantic = &&"); | |
811 | print_function_name (file, | |
812 | instruction->name, | |
4e0bf4c4 | 813 | expanded_bits, function_name_prefix_semantics); |
c906108c SS |
814 | lf_printf (file, ";\n"); |
815 | if (options.gen.semantic_icache) | |
816 | { | |
4e0bf4c4 AC |
817 | print_semantic_body (file, instruction, expanded_bits, opcodes); |
818 | print_jump (file, 1 /*is-tail */ ); | |
c906108c SS |
819 | } |
820 | else | |
821 | { | |
822 | lf_printf (file, "/* goto "); | |
823 | print_function_name (file, | |
824 | instruction->name, | |
4e0bf4c4 | 825 | expanded_bits, function_name_prefix_semantics); |
c906108c SS |
826 | lf_printf (file, "; */\n"); |
827 | } | |
828 | lf_indent (file, -2); | |
829 | lf_putstr (file, "}\n"); | |
830 | lf_indent (file, -2); | |
831 | lf_printf (file, "}\n"); | |
832 | } | |
4e0bf4c4 | 833 | |
c906108c SS |
834 | /* print the semantics */ |
835 | lf_printf (file, "\n"); | |
836 | lf_indent (file, -1); | |
837 | print_function_name (file, | |
838 | instruction->name, | |
4e0bf4c4 | 839 | expanded_bits, function_name_prefix_semantics); |
c906108c SS |
840 | lf_printf (file, ":\n"); |
841 | lf_indent (file, +1); | |
842 | lf_printf (file, "{\n"); | |
843 | lf_indent (file, +2); | |
844 | lf_putstr (file, "const unsigned_word cia = nia;\n"); | |
845 | print_icache_body (file, | |
846 | instruction, | |
847 | expanded_bits, | |
848 | cache_rules, | |
849 | (options.gen.direct_access | |
850 | ? define_variables | |
851 | : declare_variables), | |
852 | (options.gen.icache | |
4e0bf4c4 AC |
853 | ? get_values_from_icache : do_not_use_icache)); |
854 | print_semantic_body (file, instruction, expanded_bits, opcodes); | |
c906108c SS |
855 | if (options.gen.direct_access) |
856 | print_icache_body (file, | |
857 | instruction, | |
858 | expanded_bits, | |
859 | cache_rules, | |
860 | undef_variables, | |
861 | (options.gen.icache | |
4e0bf4c4 AC |
862 | ? get_values_from_icache : do_not_use_icache)); |
863 | print_jump (file, 1 /*is tail */ ); | |
c906108c SS |
864 | lf_indent (file, -2); |
865 | lf_printf (file, "}\n"); | |
866 | } | |
867 | #endif | |
868 | ||
869 | ||
870 | #if 0 | |
871 | static void | |
872 | print_jump_definition (lf *file, | |
873 | gen_entry *entry, | |
4e0bf4c4 | 874 | insn_entry * insn, int depth, void *data) |
c906108c | 875 | { |
4e0bf4c4 | 876 | cache_entry *cache_rules = (cache_entry *) data; |
c906108c SS |
877 | if (options.generate_expanded_instructions) |
878 | { | |
879 | ASSERT (entry->nr_insns == 1 | |
880 | && entry->opcode == NULL | |
4e0bf4c4 | 881 | && entry->parent != NULL && entry->parent->opcode != NULL); |
c906108c SS |
882 | ASSERT (entry->nr_insns == 1 |
883 | && entry->opcode == NULL | |
884 | && entry->parent != NULL | |
885 | && entry->parent->opcode != NULL | |
886 | && entry->parent->opcode_rule != NULL); | |
887 | print_jump_insn (file, | |
888 | entry->insns->words[0]->insn, | |
4e0bf4c4 | 889 | entry->expanded_bits, entry->opcode, cache_rules); |
c906108c SS |
890 | } |
891 | else | |
892 | { | |
893 | print_jump_insn (file, | |
4e0bf4c4 | 894 | instruction->words[0]->insn, NULL, NULL, cache_rules); |
c906108c SS |
895 | } |
896 | } | |
897 | #endif | |
898 | ||
899 | #if 0 | |
900 | static void | |
901 | print_jump_internal_function (lf *file, | |
902 | gen_entry *table, | |
4e0bf4c4 | 903 | function_entry * function, void *data) |
c906108c SS |
904 | { |
905 | if (function->is_internal) | |
906 | { | |
907 | lf_printf (file, "\n"); | |
908 | lf_print__line_ref (file, function->line); | |
909 | lf_indent (file, -1); | |
910 | print_function_name (file, | |
911 | function->name, | |
912 | NULL, | |
913 | (options.gen.icache | |
914 | ? function_name_prefix_icache | |
915 | : function_name_prefix_semantics)); | |
916 | lf_printf (file, ":\n"); | |
917 | lf_indent (file, +1); | |
918 | lf_printf (file, "{\n"); | |
919 | lf_indent (file, +2); | |
920 | lf_printf (file, "const unsigned_word cia = nia;\n"); | |
921 | table_print_code (file, function->code); | |
922 | lf_print__internal_ref (file); | |
923 | print_sim_engine_abort (file, "Internal function must longjump"); | |
924 | lf_indent (file, -2); | |
925 | lf_printf (file, "}\n"); | |
926 | } | |
927 | } | |
928 | #endif | |
929 | ||
930 | ||
931 | ||
932 | #if 0 | |
933 | static void | |
4e0bf4c4 AC |
934 | print_jump_until_stop_body (lf *file, |
935 | insn_table *table, cache_table * cache_rules) | |
c906108c SS |
936 | { |
937 | lf_printf (file, "{\n"); | |
938 | lf_indent (file, +2); | |
939 | lf_putstr (file, "jmp_buf halt;\n"); | |
940 | lf_putstr (file, "jmp_buf restart;\n"); | |
941 | lf_putstr (file, "sim_cpu *cpu = NULL;\n"); | |
942 | lf_putstr (file, "unsigned_word nia = -1;\n"); | |
943 | lf_putstr (file, "instruction_word instruction = 0;\n"); | |
4e0bf4c4 AC |
944 | if ((code & generate_with_icache)) |
945 | { | |
946 | lf_putstr (file, "idecode_cache *cache_entry = NULL;\n"); | |
947 | } | |
948 | if (generate_smp) | |
949 | { | |
950 | lf_putstr (file, "int current_cpu = -1;\n"); | |
951 | } | |
c906108c SS |
952 | |
953 | /* all the switches and tables - they know about jumping */ | |
4e0bf4c4 AC |
954 | print_idecode_lookups (file, table, cache_rules); |
955 | ||
c906108c | 956 | /* start the simulation up */ |
4e0bf4c4 AC |
957 | if ((code & generate_with_icache)) |
958 | { | |
959 | lf_putstr (file, "\n"); | |
960 | lf_putstr (file, "{\n"); | |
961 | lf_putstr (file, " int cpu_nr;\n"); | |
962 | lf_putstr (file, " for (cpu_nr = 0; cpu_nr < nr_cpus; cpu_nr++)\n"); | |
963 | lf_putstr (file, " cpu_flush_icache(cpus[cpu_nr]);\n"); | |
964 | lf_putstr (file, "}\n"); | |
965 | } | |
c906108c SS |
966 | |
967 | lf_putstr (file, "\n"); | |
968 | lf_putstr (file, "psim_set_halt_and_restart(system, &halt, &restart);\n"); | |
969 | ||
970 | lf_putstr (file, "\n"); | |
971 | lf_putstr (file, "if (setjmp(halt))\n"); | |
972 | lf_putstr (file, " return;\n"); | |
973 | ||
974 | lf_putstr (file, "\n"); | |
975 | lf_putstr (file, "setjmp(restart);\n"); | |
976 | ||
977 | lf_putstr (file, "\n"); | |
4e0bf4c4 AC |
978 | if (!generate_smp) |
979 | { | |
980 | lf_putstr (file, "cpu = cpus[0];\n"); | |
981 | lf_putstr (file, "nia = cpu_get_program_counter(cpu);\n"); | |
982 | } | |
983 | else | |
984 | { | |
985 | lf_putstr (file, "current_cpu = psim_last_cpu(system);\n"); | |
986 | } | |
c906108c | 987 | |
4e0bf4c4 AC |
988 | if (!(code & generate_with_icache)) |
989 | { | |
990 | lf_printf (file, "\n"); | |
991 | lf_indent (file, -1); | |
992 | lf_printf (file, "idecode:\n"); | |
993 | lf_indent (file, +1); | |
994 | } | |
c906108c | 995 | |
4e0bf4c4 | 996 | print_jump (file, 0 /*is_tail */ ); |
c906108c | 997 | |
4e0bf4c4 AC |
998 | if ((code & generate_with_icache)) |
999 | { | |
1000 | lf_indent (file, -1); | |
1001 | lf_printf (file, "cache_miss:\n"); | |
1002 | lf_indent (file, +1); | |
1003 | } | |
c906108c SS |
1004 | |
1005 | lf_putstr (file, "instruction\n"); | |
1006 | lf_putstr (file, " = vm_instruction_map_read(cpu_instruction_map(cpu),\n"); | |
1007 | lf_putstr (file, " cpu, nia);\n"); | |
4e0bf4c4 | 1008 | print_idecode_body (file, table, "/*IGORE*/"); |
c906108c SS |
1009 | |
1010 | /* print out a table of all the internals functions */ | |
4e0bf4c4 AC |
1011 | insn_table_traverse_function (table, |
1012 | file, NULL, print_jump_internal_function); | |
c906108c | 1013 | |
4e0bf4c4 | 1014 | /* print out a table of all the instructions */ |
c906108c | 1015 | if (generate_expanded_instructions) |
4e0bf4c4 AC |
1016 | insn_table_traverse_tree (table, file, cache_rules, 1, NULL, /* start */ |
1017 | print_jump_definition, /* leaf */ | |
1018 | NULL, /* end */ | |
1019 | NULL); /* padding */ | |
c906108c | 1020 | else |
4e0bf4c4 AC |
1021 | insn_table_traverse_insn (table, |
1022 | file, cache_rules, print_jump_definition); | |
c906108c SS |
1023 | lf_indent (file, -2); |
1024 | lf_printf (file, "}\n"); | |
1025 | } | |
1026 | #endif | |
1027 | ||
1028 | /****************************************************************/ | |
1029 | ||
1030 | ||
1031 | ||
1032 | /* Output code to do any final checks on the decoded instruction. | |
1033 | This includes things like verifying any on decoded fields have the | |
1034 | correct value and checking that (for floating point) floating point | |
1035 | hardware isn't disabled */ | |
1036 | ||
1037 | void | |
1038 | print_idecode_validate (lf *file, | |
4e0bf4c4 | 1039 | insn_entry * instruction, insn_opcodes *opcode_paths) |
c906108c SS |
1040 | { |
1041 | /* Validate: unchecked instruction fields | |
1042 | ||
1043 | If any constant fields in the instruction were not checked by the | |
1044 | idecode tables, output code to check that they have the correct | |
1045 | value here */ | |
1046 | { | |
1047 | int nr_checks = 0; | |
1048 | int word_nr; | |
1049 | lf_printf (file, "\n"); | |
1050 | lf_indent_suppress (file); | |
1051 | lf_printf (file, "#if defined (WITH_RESERVED_BITS)\n"); | |
1052 | lf_printf (file, "/* validate: "); | |
1053 | print_insn_words (file, instruction); | |
1054 | lf_printf (file, " */\n"); | |
1055 | for (word_nr = 0; word_nr < instruction->nr_words; word_nr++) | |
1056 | { | |
1057 | insn_uint check_mask = 0; | |
1058 | insn_uint check_val = 0; | |
1059 | insn_word_entry *word = instruction->word[word_nr]; | |
1060 | int bit_nr; | |
1061 | ||
1062 | /* form check_mask/check_val containing what needs to be checked | |
1063 | in the instruction */ | |
1064 | for (bit_nr = 0; bit_nr < options.insn_bit_size; bit_nr++) | |
1065 | { | |
1066 | insn_bit_entry *bit = word->bit[bit_nr]; | |
1067 | insn_field_entry *field = bit->field; | |
1068 | ||
1069 | /* Make space for the next bit */ | |
1070 | check_mask <<= 1; | |
1071 | check_val <<= 1; | |
4e0bf4c4 | 1072 | |
c906108c | 1073 | /* Only need to validate constant (and reserved) |
4e0bf4c4 | 1074 | bits. Skip any others */ |
c906108c SS |
1075 | if (field->type != insn_field_int |
1076 | && field->type != insn_field_reserved) | |
1077 | continue; | |
1078 | ||
1079 | /* Look through the list of opcode paths that lead to this | |
4e0bf4c4 AC |
1080 | instruction. See if any have failed to check the |
1081 | relevant bit */ | |
c906108c SS |
1082 | if (opcode_paths != NULL) |
1083 | { | |
1084 | insn_opcodes *entry; | |
4e0bf4c4 | 1085 | for (entry = opcode_paths; entry != NULL; entry = entry->next) |
c906108c SS |
1086 | { |
1087 | opcode_field *opcode; | |
1088 | for (opcode = entry->opcode; | |
4e0bf4c4 | 1089 | opcode != NULL; opcode = opcode->parent) |
c906108c SS |
1090 | { |
1091 | if (opcode->word_nr == word_nr | |
1092 | && opcode->first <= bit_nr | |
1093 | && opcode->last >= bit_nr) | |
1094 | /* we've decoded on this bit */ | |
1095 | break; | |
1096 | } | |
1097 | if (opcode == NULL) | |
1098 | /* the bit wasn't decoded on */ | |
1099 | break; | |
1100 | } | |
1101 | if (entry == NULL) | |
1102 | /* all the opcode paths decoded on BIT_NR, no need | |
4e0bf4c4 | 1103 | to check it */ |
c906108c SS |
1104 | continue; |
1105 | } | |
4e0bf4c4 | 1106 | |
c906108c SS |
1107 | check_mask |= 1; |
1108 | check_val |= bit->value; | |
1109 | } | |
4e0bf4c4 | 1110 | |
c906108c SS |
1111 | /* if any bits not checked by opcode tables, output code to check them */ |
1112 | if (check_mask) | |
1113 | { | |
1114 | if (nr_checks == 0) | |
1115 | { | |
1116 | lf_printf (file, "if (WITH_RESERVED_BITS)\n"); | |
1117 | lf_printf (file, " {\n"); | |
1118 | lf_indent (file, +4); | |
1119 | } | |
4e0bf4c4 | 1120 | nr_checks++; |
c906108c SS |
1121 | if (options.insn_bit_size > 32) |
1122 | { | |
4e0bf4c4 | 1123 | lf_printf (file, "if ((instruction_%d\n", word_nr); |
c906108c | 1124 | lf_printf (file, " & UNSIGNED64 (0x%08lx%08lx))\n", |
4e0bf4c4 AC |
1125 | (unsigned long) (check_mask >> 32), |
1126 | (unsigned long) (check_mask)); | |
c906108c | 1127 | lf_printf (file, " != UNSIGNED64 (0x%08lx%08lx))\n", |
4e0bf4c4 AC |
1128 | (unsigned long) (check_val >> 32), |
1129 | (unsigned long) (check_val)); | |
c906108c SS |
1130 | } |
1131 | else | |
1132 | { | |
4e0bf4c4 AC |
1133 | lf_printf (file, |
1134 | "if ((instruction_%d & 0x%08lx) != 0x%08lx)\n", | |
1135 | word_nr, (unsigned long) (check_mask), | |
1136 | (unsigned long) (check_val)); | |
c906108c SS |
1137 | } |
1138 | lf_indent (file, +2); | |
1139 | print_idecode_invalid (file, "return", invalid_illegal); | |
1140 | lf_indent (file, -2); | |
1141 | } | |
1142 | } | |
1143 | if (nr_checks > 0) | |
1144 | { | |
1145 | lf_indent (file, -4); | |
1146 | lf_printf (file, " }\n"); | |
1147 | } | |
4e0bf4c4 | 1148 | lf_indent_suppress (file); |
c906108c SS |
1149 | lf_printf (file, "#endif\n"); |
1150 | } | |
1151 | ||
1152 | /* Validate: Floating Point hardware | |
4e0bf4c4 | 1153 | |
c906108c SS |
1154 | If the simulator is being built with out floating point hardware |
1155 | (different to it being disabled in the MSR) then floating point | |
1156 | instructions are invalid */ | |
1157 | { | |
1158 | if (filter_is_member (instruction->flags, "f")) | |
1159 | { | |
1160 | lf_printf (file, "\n"); | |
1161 | lf_indent_suppress (file); | |
1162 | lf_printf (file, "#if defined(CURRENT_FLOATING_POINT)\n"); | |
1163 | lf_printf (file, "/* Validate: FP hardware exists */\n"); | |
4e0bf4c4 AC |
1164 | lf_printf (file, |
1165 | "if (CURRENT_FLOATING_POINT != HARD_FLOATING_POINT) {\n"); | |
c906108c SS |
1166 | lf_indent (file, +2); |
1167 | print_idecode_invalid (file, "return", invalid_illegal); | |
1168 | lf_indent (file, -2); | |
1169 | lf_printf (file, "}\n"); | |
1170 | lf_indent_suppress (file); | |
1171 | lf_printf (file, "#endif\n"); | |
1172 | } | |
1173 | } | |
1174 | ||
1175 | /* Validate: Floating Point available | |
1176 | ||
1177 | If floating point is not available, we enter a floating point | |
1178 | unavailable interrupt into the cache instead of the instruction | |
1179 | proper. | |
1180 | ||
1181 | The PowerPC spec requires a CSI after MSR[FP] is changed and when | |
1182 | ever a CSI occures we flush the instruction cache. */ | |
1183 | ||
1184 | { | |
1185 | if (filter_is_member (instruction->flags, "f")) | |
1186 | { | |
1187 | lf_printf (file, "\n"); | |
1188 | lf_indent_suppress (file); | |
1189 | lf_printf (file, "#if defined(IS_FP_AVAILABLE)\n"); | |
1190 | lf_printf (file, "/* Validate: FP available according to cpu */\n"); | |
1191 | lf_printf (file, "if (!IS_FP_AVAILABLE) {\n"); | |
1192 | lf_indent (file, +2); | |
4e0bf4c4 | 1193 | print_idecode_invalid (file, "return", invalid_fp_unavailable); |
c906108c SS |
1194 | lf_indent (file, -2); |
1195 | lf_printf (file, "}\n"); | |
1196 | lf_indent_suppress (file); | |
1197 | lf_printf (file, "#endif\n"); | |
1198 | } | |
1199 | } | |
4e0bf4c4 | 1200 | |
c906108c SS |
1201 | /* Validate: Validate Instruction in correct slot |
1202 | ||
1203 | Some architectures place restrictions on the slot that an | |
1204 | instruction can be issued in */ | |
1205 | ||
1206 | { | |
1207 | if (filter_is_member (instruction->options, "s") | |
1208 | || options.gen.slot_verification) | |
1209 | { | |
1210 | lf_printf (file, "\n"); | |
1211 | lf_indent_suppress (file); | |
1212 | lf_printf (file, "#if defined(IS_WRONG_SLOT)\n"); | |
4e0bf4c4 AC |
1213 | lf_printf (file, |
1214 | "/* Validate: Instruction issued in correct slot */\n"); | |
c906108c SS |
1215 | lf_printf (file, "if (IS_WRONG_SLOT) {\n"); |
1216 | lf_indent (file, +2); | |
1217 | print_idecode_invalid (file, "return", invalid_wrong_slot); | |
1218 | lf_indent (file, -2); | |
1219 | lf_printf (file, "}\n"); | |
1220 | lf_indent_suppress (file); | |
1221 | lf_printf (file, "#endif\n"); | |
1222 | } | |
1223 | } | |
4e0bf4c4 | 1224 | |
c906108c SS |
1225 | } |
1226 | ||
1227 | ||
1228 | /****************************************************************/ | |
1229 | ||
1230 | ||
1231 | void | |
1232 | print_idecode_issue_function_header (lf *file, | |
1233 | const char *processor, | |
1234 | function_decl_type decl_type, | |
1235 | int nr_prefetched_words) | |
1236 | { | |
1237 | int indent; | |
1238 | lf_printf (file, "\n"); | |
1239 | switch (decl_type) | |
1240 | { | |
1241 | case is_function_declaration: | |
1242 | lf_print__function_type_function (file, print_semantic_function_type, | |
4e0bf4c4 | 1243 | "INLINE_IDECODE", " "); |
c906108c SS |
1244 | break; |
1245 | case is_function_definition: | |
1246 | lf_print__function_type_function (file, print_semantic_function_type, | |
4e0bf4c4 | 1247 | "INLINE_IDECODE", "\n"); |
c906108c SS |
1248 | break; |
1249 | case is_function_variable: | |
1250 | print_semantic_function_type (file); | |
1251 | lf_printf (file, " (*"); | |
1252 | break; | |
1253 | } | |
1254 | indent = print_function_name (file, | |
1255 | "issue", | |
1256 | NULL, | |
1257 | processor, | |
4e0bf4c4 | 1258 | NULL, function_name_prefix_idecode); |
c906108c SS |
1259 | switch (decl_type) |
1260 | { | |
1261 | case is_function_definition: | |
1262 | indent += lf_printf (file, " ("); | |
1263 | break; | |
1264 | case is_function_declaration: | |
1265 | lf_putstr (file, "\n("); | |
1266 | indent = 1; | |
1267 | break; | |
1268 | case is_function_variable: | |
1269 | lf_putstr (file, ")\n("); | |
1270 | indent = 1; | |
1271 | break; | |
1272 | } | |
1273 | lf_indent (file, +indent); | |
1274 | print_semantic_function_formal (file, nr_prefetched_words); | |
1275 | lf_putstr (file, ")"); | |
1276 | lf_indent (file, -indent); | |
1277 | switch (decl_type) | |
1278 | { | |
1279 | case is_function_definition: | |
1280 | lf_printf (file, "\n"); | |
1281 | break; | |
1282 | case is_function_declaration: | |
1283 | case is_function_variable: | |
1284 | lf_putstr (file, ";\n"); | |
1285 | break; | |
1286 | } | |
1287 | } | |
1288 | ||
1289 | ||
1290 | ||
1291 | void | |
1292 | print_idecode_globals (lf *file) | |
1293 | { | |
1294 | lf_printf (file, "enum {\n"); | |
1295 | lf_printf (file, " /* greater or equal to zero => table */\n"); | |
1296 | lf_printf (file, " function_entry = -1,\n"); | |
1297 | lf_printf (file, " boolean_entry = -2,\n"); | |
1298 | lf_printf (file, "};\n"); | |
1299 | lf_printf (file, "\n"); | |
1300 | lf_printf (file, "typedef struct _idecode_table_entry {\n"); | |
1301 | lf_printf (file, " int shift;\n"); | |
1302 | lf_printf (file, " unsigned%d mask;\n", options.insn_bit_size); | |
1303 | lf_printf (file, " unsigned%d value;\n", options.insn_bit_size); | |
1304 | lf_printf (file, " void *function_or_table;\n"); | |
1305 | lf_printf (file, "} idecode_table_entry;\n"); | |
1306 | } |