]>
Commit | Line | Data |
---|---|---|
c906108c SS |
1 | /* This file is part of the program psim. |
2 | ||
8d64d0fd | 3 | Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney |
c906108c SS |
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 | |
3fd725ef | 7 | the Free Software Foundation; either version 3 of the License, or |
c906108c SS |
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 | |
51b318de | 16 | along with this program; if not, see <http://www.gnu.org/licenses/>. |
c906108c SS |
17 | |
18 | */ | |
19 | ||
c906108c | 20 | #include <getopt.h> |
3d52735b | 21 | #include <stdlib.h> |
c906108c SS |
22 | |
23 | #include "misc.h" | |
24 | #include "lf.h" | |
25 | #include "table.h" | |
c906108c SS |
26 | |
27 | #include "filter.h" | |
28 | ||
c906108c | 29 | #include "ld-cache.h" |
d81bb16a | 30 | #include "ld-decode.h" |
c906108c SS |
31 | #include "ld-insn.h" |
32 | ||
33 | #include "igen.h" | |
34 | ||
35 | #include "gen-model.h" | |
36 | #include "gen-icache.h" | |
37 | #include "gen-itable.h" | |
38 | #include "gen-idecode.h" | |
39 | #include "gen-semantics.h" | |
40 | #include "gen-support.h" | |
41 | ||
42 | int hi_bit_nr; | |
9b6e0cb3 | 43 | int insn_bit_size = ppc_max_insn_bit_size; |
c906108c SS |
44 | |
45 | igen_code code = generate_calls; | |
46 | ||
47 | int generate_expanded_instructions; | |
48 | int icache_size = 1024; | |
49 | int generate_smp; | |
50 | ||
51 | /****************************************************************/ | |
52 | ||
53 | static int | |
54 | print_insn_bits(lf *file, insn_bits *bits) | |
55 | { | |
56 | int nr = 0; | |
57 | if (bits == NULL) | |
58 | return nr; | |
59 | nr += print_insn_bits(file, bits->last); | |
60 | nr += lf_putchr(file, '_'); | |
61 | nr += lf_putstr(file, bits->field->val_string); | |
62 | if (bits->opcode->is_boolean && bits->value == 0) | |
63 | nr += lf_putint(file, bits->opcode->boolean_constant); | |
64 | else if (!bits->opcode->is_boolean) { | |
65 | if (bits->opcode->last < bits->field->last) | |
66 | nr += lf_putint(file, bits->value << (bits->field->last - bits->opcode->last)); | |
67 | else | |
68 | nr += lf_putint(file, bits->value); | |
69 | } | |
70 | return nr; | |
71 | } | |
72 | ||
73 | extern int | |
74 | print_function_name(lf *file, | |
75 | const char *basename, | |
76 | insn_bits *expanded_bits, | |
77 | lf_function_name_prefixes prefix) | |
78 | { | |
79 | int nr = 0; | |
80 | /* the prefix */ | |
81 | switch (prefix) { | |
82 | case function_name_prefix_semantics: | |
83 | nr += lf_putstr(file, "semantic_"); | |
84 | break; | |
85 | case function_name_prefix_idecode: | |
86 | nr += lf_printf(file, "idecode_"); | |
87 | break; | |
88 | case function_name_prefix_itable: | |
89 | nr += lf_putstr(file, "itable_"); | |
90 | break; | |
91 | case function_name_prefix_icache: | |
92 | nr += lf_putstr(file, "icache_"); | |
93 | break; | |
94 | default: | |
95 | break; | |
96 | } | |
97 | ||
98 | /* the function name */ | |
99 | { | |
100 | const char *pos; | |
101 | for (pos = basename; | |
102 | *pos != '\0'; | |
103 | pos++) { | |
104 | switch (*pos) { | |
105 | case '/': | |
106 | case '-': | |
d29d5195 MG |
107 | case '(': |
108 | case ')': | |
c906108c SS |
109 | break; |
110 | case ' ': | |
111 | nr += lf_putchr(file, '_'); | |
112 | break; | |
113 | default: | |
114 | nr += lf_putchr(file, *pos); | |
115 | break; | |
116 | } | |
117 | } | |
118 | } | |
119 | ||
120 | /* the suffix */ | |
121 | if (generate_expanded_instructions) | |
122 | nr += print_insn_bits(file, expanded_bits); | |
123 | ||
124 | return nr; | |
125 | } | |
126 | ||
127 | ||
128 | void | |
129 | print_my_defines(lf *file, | |
130 | insn_bits *expanded_bits, | |
131 | table_entry *file_entry) | |
132 | { | |
133 | /* #define MY_INDEX xxxxx */ | |
134 | lf_indent_suppress(file); | |
135 | lf_printf(file, "#undef MY_INDEX\n"); | |
136 | lf_indent_suppress(file); | |
137 | lf_printf(file, "#define MY_INDEX "); | |
138 | print_function_name(file, | |
139 | file_entry->fields[insn_name], | |
140 | NULL, | |
141 | function_name_prefix_itable); | |
142 | lf_printf(file, "\n"); | |
143 | /* #define MY_PREFIX xxxxxx */ | |
144 | lf_indent_suppress(file); | |
145 | lf_printf(file, "#undef MY_PREFIX\n"); | |
146 | lf_indent_suppress(file); | |
147 | lf_printf(file, "#define MY_PREFIX "); | |
148 | print_function_name(file, | |
149 | file_entry->fields[insn_name], | |
150 | expanded_bits, | |
151 | function_name_prefix_none); | |
152 | lf_printf(file, "\n"); | |
153 | } | |
154 | ||
155 | ||
156 | void | |
157 | print_itrace(lf *file, | |
158 | table_entry *file_entry, | |
159 | int idecode) | |
160 | { | |
7811c758 | 161 | lf_print__external_ref(file, file_entry->line_nr, file_entry->file_name); |
c906108c SS |
162 | lf_printf(file, "ITRACE(trace_%s, (\"%s %s\\n\"));\n", |
163 | (idecode ? "idecode" : "semantics"), | |
164 | (idecode ? "idecode" : "semantics"), | |
165 | file_entry->fields[insn_name]); | |
7811c758 | 166 | lf_print__internal_ref(file); |
c906108c SS |
167 | } |
168 | ||
169 | ||
170 | /****************************************************************/ | |
171 | ||
172 | ||
173 | static void | |
174 | gen_semantics_h(insn_table *table, | |
175 | lf *file, | |
176 | igen_code generate) | |
177 | { | |
178 | lf_printf(file, "typedef %s idecode_semantic\n(%s);\n", | |
179 | SEMANTIC_FUNCTION_TYPE, | |
180 | SEMANTIC_FUNCTION_FORMAL); | |
181 | lf_printf(file, "\n"); | |
182 | if ((code & generate_calls)) { | |
c906108c | 183 | lf_printf(file, "extern int option_mpc860c0;\n"); |
a49dd19e | 184 | lf_printf(file, "#define MPC860C0_PAGE_SIZE 0x1000\n"); |
c906108c | 185 | lf_printf(file, "\n"); |
d29d5195 | 186 | lf_printf(file, "PSIM_EXTERN_SEMANTICS(void)\n"); |
c906108c SS |
187 | lf_printf(file, "semantic_init(device* root);\n"); |
188 | lf_printf(file, "\n"); | |
c906108c SS |
189 | if (generate_expanded_instructions) |
190 | insn_table_traverse_tree(table, | |
191 | file, NULL, | |
192 | 1, | |
193 | NULL, /* start */ | |
194 | print_semantic_declaration, /* leaf */ | |
195 | NULL, /* end */ | |
196 | NULL); /* padding */ | |
197 | else | |
198 | insn_table_traverse_insn(table, | |
199 | file, NULL, | |
200 | print_semantic_declaration); | |
201 | ||
202 | } | |
203 | else { | |
7811c758 | 204 | lf_print__this_file_is_empty(file, "generating jumps"); |
c906108c SS |
205 | } |
206 | } | |
207 | ||
208 | ||
209 | static void | |
210 | gen_semantics_c(insn_table *table, | |
211 | cache_table *cache_rules, | |
212 | lf *file, | |
213 | igen_code generate) | |
214 | { | |
215 | if ((code & generate_calls)) { | |
216 | lf_printf(file, "\n"); | |
217 | lf_printf(file, "#include \"cpu.h\"\n"); | |
218 | lf_printf(file, "#include \"idecode.h\"\n"); | |
219 | lf_printf(file, "#include \"semantics.h\"\n"); | |
be2bc30f | 220 | lf_printf(file, "#include \"tree.h\"\n"); |
8d64d0fd | 221 | lf_printf(file, "#ifdef HAVE_COMMON_FPU\n"); |
d29d5195 MG |
222 | lf_printf(file, "#include \"sim-inline.h\"\n"); |
223 | lf_printf(file, "#include \"sim-fpu.h\"\n"); | |
8d64d0fd AC |
224 | lf_printf(file, "#endif\n"); |
225 | lf_printf(file, "#include \"support.h\"\n"); | |
c906108c | 226 | lf_printf(file, "\n"); |
c906108c SS |
227 | lf_printf(file, "int option_mpc860c0 = 0;\n"); |
228 | lf_printf(file, "\n"); | |
d29d5195 | 229 | lf_printf(file, "PSIM_EXTERN_SEMANTICS(void)\n"); |
c906108c SS |
230 | lf_printf(file, "semantic_init(device* root)\n"); |
231 | lf_printf(file, "{\n"); | |
232 | lf_printf(file, " option_mpc860c0 = 0;\n"); | |
233 | lf_printf(file, " if (tree_find_property(root, \"/options/mpc860c0\"))\n"); | |
234 | lf_printf(file, " option_mpc860c0 = tree_find_integer_property(root, \"/options/mpc860c0\");\n"); | |
c96b63a2 | 235 | lf_printf(file, " option_mpc860c0 *= 4; /* convert word count to byte count */\n"); |
c906108c SS |
236 | lf_printf(file, "}\n"); |
237 | lf_printf(file, "\n"); | |
c906108c SS |
238 | if (generate_expanded_instructions) |
239 | insn_table_traverse_tree(table, | |
240 | file, cache_rules, | |
241 | 1, | |
242 | NULL, /* start */ | |
243 | print_semantic_definition, /* leaf */ | |
244 | NULL, /* end */ | |
245 | NULL); /* padding */ | |
246 | else | |
247 | insn_table_traverse_insn(table, | |
248 | file, cache_rules, | |
249 | print_semantic_definition); | |
250 | ||
251 | } | |
252 | else { | |
7811c758 | 253 | lf_print__this_file_is_empty(file, "generating jump engine"); |
c906108c SS |
254 | } |
255 | } | |
256 | ||
257 | ||
258 | /****************************************************************/ | |
259 | ||
260 | ||
261 | static void | |
262 | gen_icache_h(insn_table *table, | |
263 | lf *file, | |
264 | igen_code generate) | |
265 | { | |
266 | lf_printf(file, "typedef %s idecode_icache\n(%s);\n", | |
267 | ICACHE_FUNCTION_TYPE, | |
268 | ICACHE_FUNCTION_FORMAL); | |
269 | lf_printf(file, "\n"); | |
270 | if ((code & generate_calls) | |
271 | && (code & generate_with_icache)) { | |
272 | insn_table_traverse_function(table, | |
273 | file, NULL, | |
274 | print_icache_internal_function_declaration); | |
275 | if (generate_expanded_instructions) | |
276 | insn_table_traverse_tree(table, | |
277 | file, NULL, | |
278 | 1, | |
279 | NULL, /* start */ | |
280 | print_icache_declaration, /* leaf */ | |
281 | NULL, /* end */ | |
282 | NULL); /* padding */ | |
283 | else | |
284 | insn_table_traverse_insn(table, | |
285 | file, NULL, | |
286 | print_icache_declaration); | |
287 | ||
288 | } | |
289 | else { | |
7811c758 | 290 | lf_print__this_file_is_empty(file, "generating jump engine"); |
c906108c SS |
291 | } |
292 | } | |
293 | ||
294 | static void | |
295 | gen_icache_c(insn_table *table, | |
296 | cache_table *cache_rules, | |
297 | lf *file, | |
298 | igen_code generate) | |
299 | { | |
300 | /* output `internal' invalid/floating-point unavailable functions | |
301 | where needed */ | |
302 | if ((code & generate_calls) | |
303 | && (code & generate_with_icache)) { | |
304 | lf_printf(file, "\n"); | |
305 | lf_printf(file, "#include \"cpu.h\"\n"); | |
306 | lf_printf(file, "#include \"idecode.h\"\n"); | |
307 | lf_printf(file, "#include \"semantics.h\"\n"); | |
308 | lf_printf(file, "#include \"icache.h\"\n"); | |
8d64d0fd | 309 | lf_printf(file, "#ifdef HAVE_COMMON_FPU\n"); |
d29d5195 MG |
310 | lf_printf(file, "#include \"sim-inline.h\"\n"); |
311 | lf_printf(file, "#include \"sim-fpu.h\"\n"); | |
8d64d0fd AC |
312 | lf_printf(file, "#endif\n"); |
313 | lf_printf(file, "#include \"support.h\"\n"); | |
c906108c SS |
314 | lf_printf(file, "\n"); |
315 | insn_table_traverse_function(table, | |
316 | file, NULL, | |
317 | print_icache_internal_function_definition); | |
318 | lf_printf(file, "\n"); | |
319 | if (generate_expanded_instructions) | |
320 | insn_table_traverse_tree(table, | |
321 | file, cache_rules, | |
322 | 1, | |
323 | NULL, /* start */ | |
324 | print_icache_definition, /* leaf */ | |
325 | NULL, /* end */ | |
326 | NULL); /* padding */ | |
327 | else | |
328 | insn_table_traverse_insn(table, | |
329 | file, cache_rules, | |
330 | print_icache_definition); | |
331 | ||
332 | } | |
333 | else { | |
7811c758 | 334 | lf_print__this_file_is_empty(file, "generating jump engine"); |
c906108c SS |
335 | } |
336 | } | |
337 | ||
338 | ||
339 | /****************************************************************/ | |
340 | ||
341 | ||
342 | int | |
343 | main(int argc, | |
344 | char **argv, | |
345 | char **envp) | |
346 | { | |
347 | cache_table *cache_rules = NULL; | |
348 | lf_file_references file_references = lf_include_references; | |
349 | decode_table *decode_rules = NULL; | |
350 | filter *filters = NULL; | |
351 | insn_table *instructions = NULL; | |
43c4bab0 | 352 | table_include *includes = NULL; |
dd6c5a92 | 353 | static const struct option longopts[] = { { 0 } }; |
c906108c SS |
354 | char *real_file_name = NULL; |
355 | int is_header = 0; | |
356 | int ch; | |
357 | ||
358 | if (argc == 1) { | |
359 | printf("Usage:\n"); | |
360 | printf(" igen <config-opts> ... <input-opts>... <output-opts>...\n"); | |
361 | printf("Config options:\n"); | |
362 | printf(" -F <filter-out-flag> eg -F 64 to skip 64bit instructions\n"); | |
363 | printf(" -E Expand (duplicate) semantic functions\n"); | |
364 | printf(" -I <icache-size> Generate cracking cache version\n"); | |
365 | printf(" -C Include semantics in cache functions\n"); | |
366 | printf(" -S Include insn (instruction) in icache\n"); | |
367 | printf(" -R Use defines to reference cache vars\n"); | |
368 | printf(" -L Supress line numbering in output files\n"); | |
369 | printf(" -B <bit-size> Set the number of bits in an instruction\n"); | |
370 | printf(" -H <high-bit> Set the nr of the high (msb bit)\n"); | |
371 | printf(" -N <nr-cpus> Specify the max number of cpus the simulation will support\n"); | |
372 | printf(" -J Use jumps instead of function calls\n"); | |
373 | printf(" -T <mechanism> Override the mechanism used to decode an instruction\n"); | |
374 | printf(" using <mechanism> instead of what was specified in the\n"); | |
375 | printf(" decode-rules input file\n"); | |
376 | printf("\n"); | |
377 | printf("Input options (ucase version also dumps loaded table):\n"); | |
378 | printf(" -o <decode-rules>\n"); | |
379 | printf(" -k <cache-rules>\n"); | |
380 | printf(" -i <instruction-table>\n"); | |
381 | printf("\n"); | |
382 | printf("Output options:\n"); | |
383 | printf(" -n <real-name> Specify the real name of for the next output file\n"); | |
384 | printf(" -h Generate header file\n"); | |
385 | printf(" -c <output-file> output icache\n"); | |
386 | printf(" -d <output-file> output idecode\n"); | |
387 | printf(" -m <output-file> output model\n"); | |
388 | printf(" -s <output-file> output schematic\n"); | |
389 | printf(" -t <output-file> output itable\n"); | |
390 | printf(" -f <output-file> output support functions\n"); | |
391 | } | |
392 | ||
dd6c5a92 TO |
393 | while ( |
394 | (ch = getopt_long (argc, argv, "F:EI:RSLJT:CB:H:N:o:k:i:n:hc:d:m:s:t:f:", | |
395 | longopts, NULL)) | |
396 | != -1) | |
397 | { | |
c26c6bc0 | 398 | #if 0 /* For debugging. */ |
c906108c | 399 | fprintf(stderr, "\t-%c %s\n", ch, (optarg ? optarg : "")); |
c26c6bc0 | 400 | #endif |
c906108c SS |
401 | switch(ch) { |
402 | case 'C': | |
403 | code |= generate_with_icache; | |
404 | code |= generate_with_semantic_icache; | |
405 | break; | |
406 | case 'S': | |
407 | code |= generate_with_icache; | |
408 | code |= generate_with_insn_in_icache; | |
409 | break; | |
410 | case 'L': | |
411 | file_references = lf_omit_references; | |
412 | break; | |
413 | case 'E': | |
414 | generate_expanded_instructions = 1; | |
415 | break; | |
43c4bab0 MG |
416 | case 'G': |
417 | { | |
418 | int enable_p; | |
419 | char *argp; | |
420 | if (strncmp (optarg, "no-", strlen ("no-")) == 0) | |
421 | { | |
422 | argp = optarg + strlen ("no-"); | |
423 | enable_p = 0; | |
424 | } | |
425 | else if (strncmp (optarg, "!", strlen ("!")) == 0) | |
426 | { | |
427 | argp = optarg + strlen ("no-"); | |
428 | enable_p = 0; | |
429 | } | |
430 | else | |
431 | { | |
432 | argp = optarg; | |
433 | enable_p = 1; | |
434 | } | |
435 | if (strncmp (argp, "gen-icache", strlen ("gen-icache")) == 0) | |
436 | { | |
437 | switch (argp[strlen ("gen-icache")]) | |
438 | { | |
439 | case '=': | |
440 | icache_size = atoi (argp + strlen ("gen-icache") + 1); | |
866a2ad3 MF |
441 | if (enable_p) |
442 | code |= generate_with_icache; | |
443 | else | |
444 | code &= ~generate_with_icache; | |
43c4bab0 MG |
445 | break; |
446 | case '\0': | |
866a2ad3 MF |
447 | if (enable_p) |
448 | code |= generate_with_icache; | |
449 | else | |
450 | code &= ~generate_with_icache; | |
43c4bab0 MG |
451 | break; |
452 | default: | |
9ddac092 | 453 | ERROR ("Expecting -Ggen-icache or -Ggen-icache=<N>\n"); |
43c4bab0 MG |
454 | } |
455 | } | |
866a2ad3 | 456 | break; |
43c4bab0 | 457 | } |
c906108c | 458 | case 'I': |
43c4bab0 MG |
459 | { |
460 | table_include **dir = &includes; | |
461 | while ((*dir) != NULL) | |
462 | dir = &(*dir)->next; | |
463 | (*dir) = ZALLOC (table_include); | |
464 | (*dir)->dir = strdup (optarg); | |
465 | } | |
c906108c SS |
466 | break; |
467 | case 'N': | |
468 | generate_smp = a2i(optarg); | |
469 | break; | |
470 | case 'R': | |
471 | code |= generate_with_direct_access; | |
472 | break; | |
473 | case 'B': | |
474 | insn_bit_size = a2i(optarg); | |
9b6e0cb3 | 475 | ASSERT(insn_bit_size > 0 && insn_bit_size <= ppc_max_insn_bit_size |
c906108c SS |
476 | && (hi_bit_nr == insn_bit_size-1 || hi_bit_nr == 0)); |
477 | break; | |
478 | case 'H': | |
479 | hi_bit_nr = a2i(optarg); | |
480 | ASSERT(hi_bit_nr == insn_bit_size-1 || hi_bit_nr == 0); | |
481 | break; | |
482 | case 'F': | |
086d7dbb | 483 | filter_parse(&filters, optarg); |
c906108c SS |
484 | break; |
485 | case 'J': | |
486 | code &= ~generate_calls; | |
487 | code |= generate_jumps; | |
488 | break; | |
489 | case 'T': | |
490 | force_decode_gen_type(optarg); | |
491 | break; | |
492 | case 'i': | |
d81bb16a AC |
493 | if (decode_rules == NULL) { |
494 | fprintf(stderr, "Must specify decode tables\n"); | |
c906108c SS |
495 | exit (1); |
496 | } | |
d81bb16a AC |
497 | instructions = load_insn_table(optarg, decode_rules, filters, includes, |
498 | &cache_rules); | |
c906108c SS |
499 | fprintf(stderr, "\texpanding ...\n"); |
500 | insn_table_expand_insns(instructions); | |
501 | break; | |
502 | case 'o': | |
503 | decode_rules = load_decode_table(optarg, hi_bit_nr); | |
504 | break; | |
505 | case 'k': | |
506 | cache_rules = load_cache_table(optarg, hi_bit_nr); | |
507 | break; | |
508 | case 'n': | |
509 | real_file_name = strdup(optarg); | |
510 | break; | |
511 | case 'h': | |
512 | is_header = 1; | |
513 | break; | |
514 | case 's': | |
515 | case 'd': | |
516 | case 'm': | |
517 | case 't': | |
518 | case 'f': | |
519 | case 'c': | |
520 | { | |
521 | lf *file = lf_open(optarg, real_file_name, file_references, | |
522 | (is_header ? lf_is_h : lf_is_c), | |
523 | argv[0]); | |
524 | lf_print__file_start(file); | |
525 | ASSERT(instructions != NULL); | |
526 | switch (ch) { | |
527 | case 's': | |
528 | if(is_header) | |
529 | gen_semantics_h(instructions, file, code); | |
530 | else | |
531 | gen_semantics_c(instructions, cache_rules, file, code); | |
532 | break; | |
533 | case 'd': | |
534 | if (is_header) | |
535 | gen_idecode_h(file, instructions, cache_rules); | |
536 | else | |
537 | gen_idecode_c(file, instructions, cache_rules); | |
538 | break; | |
539 | case 'm': | |
540 | if (is_header) | |
541 | gen_model_h(instructions, file); | |
542 | else | |
543 | gen_model_c(instructions, file); | |
544 | break; | |
545 | case 't': | |
546 | if (is_header) | |
547 | gen_itable_h(instructions, file); | |
548 | else | |
549 | gen_itable_c(instructions, file); | |
550 | break; | |
551 | case 'f': | |
552 | if (is_header) | |
553 | gen_support_h(instructions, file); | |
554 | else | |
555 | gen_support_c(instructions, file); | |
556 | break; | |
557 | case 'c': | |
558 | if (is_header) | |
559 | gen_icache_h(instructions, file, code); | |
560 | else | |
561 | gen_icache_c(instructions, cache_rules, file, code); | |
562 | break; | |
563 | } | |
564 | lf_print__file_finish(file); | |
565 | lf_close(file); | |
566 | is_header = 0; | |
567 | } | |
568 | real_file_name = NULL; | |
569 | break; | |
570 | default: | |
9ddac092 | 571 | ERROR("unknown option\n"); |
c906108c SS |
572 | } |
573 | } | |
574 | return 0; | |
575 | } |