extern void print_icache_struct (lf *file, insn_table *isa, cache_entry *cache_rules) { /* Create a list of all the different instruction formats with their corresponding field names. */ form_fields *formats = insn_table_cache_fields (isa); lf_printf (file, "\n"); lf_printf (file, "#define WITH_%sIDECODE_CACHE_SIZE %d\n", options.module.global.prefix.u, (options.gen.icache ? options.gen.icache_size : 0)); lf_printf (file, "\n"); /* create an instruction cache if being used */ if (options.gen.icache) { lf_printf (file, "typedef struct _%sidecode_cache {\n", options.module.global.prefix.l); lf_indent (file, +2); { form_fields *format; lf_printf (file, "unsigned_word address;\n"); lf_printf (file, "void *semantic;\n"); lf_printf (file, "union {\n"); lf_indent (file, +2); for (format = formats; format != NULL; format = format->next) { lf_printf (file, "struct {\n"); lf_indent (file, +2); { cache_entry *cache_rule; char *field; /* space for any instruction words */ if (options.gen.insn_in_icache) lf_printf (file, "instruction_word insn[%d];\n", isa->max_nr_words); /* define an entry for any applicable cache rules */ for (cache_rule = cache_rules; cache_rule != NULL; cache_rule = cache_rule->next) { /* nb - sort of correct - should really check against individual instructions */ if (filter_is_subset (format->fields, cache_rule->original_fields)) { char *memb; lf_printf (file, "%s %s;", (cache_rule->type == NULL ? "unsigned" : cache_rule->type), cache_rule->name); lf_printf (file, " /*"); for (memb = filter_next (cache_rule->original_fields, ""); memb != NULL; memb = filter_next (cache_rule->original_fields, memb)) { lf_printf (file, " %s", memb); } lf_printf (file, " */\n"); } } /* define an entry for any fields not covered by a cache rule */ for (field = filter_next (format->fields, ""); field != NULL; field = filter_next (format->fields, field)) { cache_entry *cache_rule; int found_rule = 0; for (cache_rule = cache_rules; cache_rule != NULL; cache_rule = cache_rule->next) { if (strcmp (cache_rule->name, field) == 0) { found_rule = 1; break; } } if (!found_rule) lf_printf (file, "unsigned %s; /* default */\n", field); } } lf_indent (file, -2); lf_printf (file, "} %s;\n", format->name); } lf_indent (file, -2); lf_printf (file, "} crack;\n"); } lf_indent (file, -2); lf_printf (file, "} %sidecode_cache;\n", options.module.global.prefix.l); } else { /* alernativly, since no cache, emit a dummy definition for idecode_cache so that code refering to the type can still compile */ lf_printf (file, "typedef void %sidecode_cache;\n", options.module.global.prefix.l); } lf_printf (file, "\n"); }
static void print_icache_function (lf *file, insn_entry * instruction, opcode_bits *expanded_bits, insn_opcodes *opcodes, cache_entry *cache_rules, int nr_prefetched_words) { int indent; /* generate code to enter decoded instruction into the icache */ lf_printf (file, "\n"); lf_print__function_type_function (file, print_icache_function_type, "EXTERN_ICACHE", "\n"); indent = print_function_name (file, instruction->name, instruction->format_name, NULL, expanded_bits, function_name_prefix_icache); indent += lf_printf (file, " "); lf_indent (file, +indent); lf_printf (file, "("); print_icache_function_formal (file, nr_prefetched_words); lf_printf (file, ")\n"); lf_indent (file, -indent); /* function header */ lf_printf (file, "{\n"); lf_indent (file, +2); print_my_defines (file, instruction->name, instruction->format_name, expanded_bits); print_itrace (file, instruction, 1 /*putting-value-in-cache */ ); print_idecode_validate (file, instruction, opcodes); lf_printf (file, "\n"); lf_printf (file, "{\n"); lf_indent (file, +2); if (options.gen.semantic_icache) lf_printf (file, "unsigned_word nia;\n"); print_icache_body (file, instruction, expanded_bits, cache_rules, (options.gen.direct_access ? define_variables : declare_variables), (options.gen.semantic_icache ? both_values_and_icache : put_values_in_icache), nr_prefetched_words); lf_printf (file, "\n"); lf_printf (file, "cache_entry->address = cia;\n"); lf_printf (file, "cache_entry->semantic = "); print_function_name (file, instruction->name, instruction->format_name, NULL, expanded_bits, function_name_prefix_semantics); lf_printf (file, ";\n"); lf_printf (file, "\n"); if (options.gen.semantic_icache) { lf_printf (file, "/* semantic routine */\n"); print_semantic_body (file, instruction, expanded_bits, opcodes); lf_printf (file, "return nia;\n"); } if (!options.gen.semantic_icache) { lf_printf (file, "/* return the function proper */\n"); lf_printf (file, "return "); print_function_name (file, instruction->name, instruction->format_name, NULL, expanded_bits, function_name_prefix_semantics); lf_printf (file, ";\n"); } if (options.gen.direct_access) { print_icache_body (file, instruction, expanded_bits, cache_rules, undef_variables, (options.gen.semantic_icache ? both_values_and_icache : put_values_in_icache), nr_prefetched_words); } lf_indent (file, -2); lf_printf (file, "}\n"); lf_indent (file, -2); lf_printf (file, "}\n"); }
void print_semantic_body(lf *file, insn *instruction, insn_bits *expanded_bits, opcode_field *opcodes) { print_itrace(file, instruction->file_entry, 0/*put_value_in_cache*/); /* validate the instruction, if a cache this has already been done */ if (!(code & generate_with_icache)) print_idecode_validate(file, instruction, opcodes); /* generate the profiling call - this is delayed until after the instruction has been verified */ lf_printf(file, "\n"); lf_printf(file, "/* monitoring: */\n"); lf_printf(file, "if (WITH_MON & MONITOR_INSTRUCTION_ISSUE) {\n"); lf_printf(file, " mon_issue("); print_function_name(file, instruction->file_entry->fields[insn_name], NULL, function_name_prefix_itable); lf_printf(file, ", processor, cia);\n"); lf_printf(file, "}\n"); /* generate the code (or at least something */ lf_printf(file, "\n"); lf_printf(file, "/* semantics: */\n"); lf_printf(file, "nia = cia + %d;\n", insn_bit_size / 8); if (instruction->file_entry->annex != NULL) { /* true code */ table_entry_print_cpp_line_nr(file, instruction->file_entry); lf_printf(file, "{\n"); lf_indent(file, +2); lf_print__c_code(file, instruction->file_entry->annex); lf_indent(file, -2); lf_printf(file, "}\n"); lf_print__internal_reference(file); } else if (it_is("nop", instruction->file_entry->fields[insn_flags])) { lf_print__internal_reference(file); } else { /* abort so it is implemented now */ table_entry_print_cpp_line_nr(file, instruction->file_entry); lf_putstr(file, "error(\"%s:%d:0x%08lx:%s unimplemented\\n\",\n"); lf_printf(file, " itable[MY_INDEX].file, itable[MY_INDEX].line_nr, (long)cia, itable[MY_INDEX].name);\n"); lf_print__internal_reference(file); } }
void print_icache_body (lf *file, insn_entry * instruction, opcode_bits *expanded_bits, cache_entry *cache_rules, icache_decl_type what_to_declare, icache_body_type what_to_do, int nr_prefetched_words) { /* extract instruction fields */ lf_printf (file, "/* Extraction: %s\n", instruction->name); lf_printf (file, " "); switch (what_to_declare) { case define_variables: lf_printf (file, "#define"); break; case declare_variables: lf_printf (file, "declare"); break; case undef_variables: lf_printf (file, "#undef"); break; } lf_printf (file, " "); switch (what_to_do) { case get_values_from_icache: lf_printf (file, "get-values-from-icache"); break; case put_values_in_icache: lf_printf (file, "put-values-in-icache"); break; case both_values_and_icache: lf_printf (file, "get-values-from-icache|put-values-in-icache"); break; case do_not_use_icache: lf_printf (file, "do-not-use-icache"); break; } lf_printf (file, "\n "); print_insn_words (file, instruction); lf_printf (file, " */\n"); /* pass zero - fetch from memory any missing instructions. Some of the instructions will have already been fetched (in the instruction array), others will still need fetching. */ switch (what_to_do) { case get_values_from_icache: break; case put_values_in_icache: case both_values_and_icache: case do_not_use_icache: { int word_nr; switch (what_to_declare) { case undef_variables: break; case define_variables: case declare_variables: for (word_nr = nr_prefetched_words; word_nr < instruction->nr_words; word_nr++) { /* FIXME - should be using print_icache_extraction? */ lf_printf (file, "%sinstruction_word instruction_%d UNUSED = ", options.module.global.prefix.l, word_nr); lf_printf (file, "IMEM%d_IMMED (cia, %d)", options.insn_bit_size, word_nr); lf_printf (file, ";\n"); } } } } /* if putting the instruction words in the cache, define references for them */ if (options.gen.insn_in_icache) { /* FIXME: is the instruction_word type correct? */ print_icache_extraction (file, instruction->format_name, cache_value, "insn", /* name */ "instruction_word", /* type */ "instruction", /* expression */ NULL, /* origin */ NULL, /* line */ NULL, NULL, what_to_declare, what_to_do); } lf_printf (file, "\n"); /* pass one - process instruction fields. If there is no cache rule, the default is to enter the field into the cache */ { insn_word_entry *word; for (word = instruction->words; word != NULL; word = word->next) { insn_field_entry *cur_field; for (cur_field = word->first; cur_field->first < options.insn_bit_size; cur_field = cur_field->next) { /* Always expand named fields (even if constant), so references are valid. */ if (cur_field->type == insn_field_string) { cache_entry *cache_rule; cache_entry_type value_type = cache_value; line_ref *value_line = instruction->line; /* check the cache table to see if it contains a rule overriding the default cache action for an instruction field */ for (cache_rule = cache_rules; cache_rule != NULL; cache_rule = cache_rule->next) { if (filter_is_subset (instruction->field_names, cache_rule->original_fields) && strcmp (cache_rule->name, cur_field->val_string) == 0) { value_type = cache_rule->entry_type; value_line = cache_rule->line; if (value_type == compute_value) { options.warning (cache_rule->line, "instruction field of type `compute' changed to `cache'\n"); cache_rule->entry_type = cache_value; } break; } } /* Define an entry for the field within the instruction */ print_icache_extraction (file, instruction->format_name, value_type, cur_field->val_string, /* name */ NULL, /* type */ NULL, /* expression */ cur_field->val_string, /* insn field */ value_line, cur_field, expanded_bits, what_to_declare, what_to_do); } } } } /* pass two - any cache fields not processed above */ { cache_entry *cache_rule; for (cache_rule = cache_rules; cache_rule != NULL; cache_rule = cache_rule->next) { if (filter_is_subset (instruction->field_names, cache_rule->original_fields) && !filter_is_member (instruction->field_names, cache_rule->name)) { char *single_field = filter_next (cache_rule->original_fields, ""); if (filter_next (cache_rule->original_fields, single_field) != NULL) single_field = NULL; print_icache_extraction (file, instruction->format_name, cache_rule->entry_type, cache_rule->name, cache_rule->type, cache_rule->expression, single_field, cache_rule->line, NULL, /* cur_field */ expanded_bits, what_to_declare, what_to_do); } } } lf_print__internal_ref (file); }
extern int print_function_name (lf *file, const char *basename, const char *format_name, const char *model_name, opcode_bits *expanded_bits, lf_function_name_prefixes prefix) { int nr = 0; /* the prefix */ switch (prefix) { case function_name_prefix_semantics: nr += lf_printf (file, "%s", options.module.semantics.prefix.l); nr += lf_printf (file, "semantic_"); break; case function_name_prefix_idecode: nr += lf_printf (file, "%s", options.module.idecode.prefix.l); nr += lf_printf (file, "idecode_"); break; case function_name_prefix_itable: nr += lf_printf (file, "%sitable_", options.module.itable.prefix.l); break; case function_name_prefix_icache: nr += lf_printf (file, "%s", options.module.icache.prefix.l); nr += lf_printf (file, "icache_"); break; case function_name_prefix_engine: nr += lf_printf (file, "%s", options.module.engine.prefix.l); nr += lf_printf (file, "engine_"); default: break; } if (model_name != NULL) { nr += print_c_name (file, model_name); nr += lf_printf (file, "_"); } /* the function name */ nr += print_c_name (file, basename); /* the format name if available */ if (format_name != NULL) { nr += lf_printf (file, "_"); nr += print_c_name (file, format_name); } /* the suffix */ nr += print_opcode_bits (file, expanded_bits); return nr; }
void print_semantic_body (lf *file, insn_entry * instruction, opcode_bits *expanded_bits, insn_opcodes *opcodes) { /* validate the instruction, if a cache this has already been done */ if (!options.gen.icache) { print_idecode_validate (file, instruction, opcodes); } print_itrace (file, instruction, 0 /*put_value_in_cache */ ); /* generate the instruction profile call - this is delayed until after the instruction has been verified. The count macro generated is prefixed by ITABLE_PREFIX */ { lf_printf (file, "\n"); lf_indent_suppress (file); lf_printf (file, "#if defined (%sPROFILE_COUNT_INSN)\n", options.module.itable.prefix.u); lf_printf (file, "%sPROFILE_COUNT_INSN (CPU, CIA, MY_INDEX);\n", options.module.itable.prefix.u); lf_indent_suppress (file); lf_printf (file, "#endif\n"); } /* generate the model call - this is delayed until after the instruction has been verified */ { lf_printf (file, "\n"); lf_indent_suppress (file); lf_printf (file, "#if defined (WITH_MON)\n"); lf_printf (file, "/* monitoring: */\n"); lf_printf (file, "if (WITH_MON & MONITOR_INSTRUCTION_ISSUE)\n"); lf_printf (file, " mon_issue ("); print_function_name (file, instruction->name, instruction->format_name, NULL, NULL, function_name_prefix_itable); lf_printf (file, ", cpu, cia);\n"); lf_indent_suppress (file); lf_printf (file, "#endif\n"); lf_printf (file, "\n"); } /* determine the new instruction address */ { lf_printf (file, "/* keep the next instruction address handy */\n"); if (options.gen.nia == nia_is_invalid) { lf_printf (file, "nia = %sINVALID_INSTRUCTION_ADDRESS;\n", options.module.global.prefix.u); } else { int nr_immeds = instruction->nr_words - 1; if (options.gen.delayed_branch) { if (nr_immeds > 0) { lf_printf (file, "cia.dp += %d * %d; %s\n", options.insn_bit_size / 8, nr_immeds, "/* skip dp immeds */"); } lf_printf (file, "nia.ip = cia.dp; %s\n", "/* instruction pointer */"); lf_printf (file, "nia.dp = cia.dp + %d; %s\n", options.insn_bit_size / 8, "/* delayed-slot pointer */"); } else { if (nr_immeds > 0) { lf_printf (file, "nia = cia + %d * (%d + 1); %s\n", options.insn_bit_size / 8, nr_immeds, "/* skip immeds as well */"); } else { lf_printf (file, "nia = cia + %d;\n", options.insn_bit_size / 8); } } } } /* if conditional, generate code to verify that the instruction should be issued */ if (filter_is_member (instruction->options, "c") || options.gen.conditional_issue) { lf_printf (file, "\n"); lf_printf (file, "/* execute only if conditional passes */\n"); lf_printf (file, "if (IS_CONDITION_OK)\n"); lf_printf (file, " {\n"); lf_indent (file, +4); /* FIXME - need to log a conditional failure */ } /* Architecture expects a REG to be zero. Instead of having to check every read to see if it is refering to that REG just zap it at the start of every instruction */ if (options.gen.zero_reg) { lf_printf (file, "\n"); lf_printf (file, "/* Architecture expects REG to be zero */\n"); lf_printf (file, "GPR_CLEAR(%d);\n", options.gen.zero_reg_nr); } /* generate the code (or at least something */ lf_printf (file, "\n"); lf_printf (file, "/* semantics: */\n"); if (instruction->code != NULL) { /* true code */ lf_printf (file, "{\n"); lf_indent (file, +2); lf_print__line_ref (file, instruction->code->line); table_print_code (file, instruction->code); lf_indent (file, -2); lf_printf (file, "}\n"); lf_print__internal_ref (file); } else if (filter_is_member (instruction->options, "nop")) { lf_print__internal_ref (file); } else { const char *prefix = "sim_engine_abort ("; int indent = strlen (prefix); /* abort so it is implemented now */ lf_print__line_ref (file, instruction->line); lf_printf (file, "%sSD, CPU, cia, \\\n", prefix); lf_indent (file, +indent); lf_printf (file, "\"%s:%d:0x%%08lx:%%s unimplemented\\n\", \\\n", filter_filename (instruction->line->file_name), instruction->line->line_nr); lf_printf (file, "(long) CIA, \\\n"); lf_printf (file, "%sitable[MY_INDEX].name);\n", options.module.itable.prefix.l); lf_indent (file, -indent); lf_print__internal_ref (file); } /* Close off the conditional execution */ if (filter_is_member (instruction->options, "c") || options.gen.conditional_issue) { lf_indent (file, -4); lf_printf (file, " }\n"); } }
void gen_model_c(insn_table *table, lf *file) { insn *insn_ptr; model *model_ptr; char *name; int model_create_p = 0; int model_init_p = 0; int model_halt_p = 0; int model_mon_info_p = 0; int model_mon_info_free_p = 0; lf_printf(file, "\n"); lf_printf(file, "#include \"cpu.h\"\n"); lf_printf(file, "#include \"mon.h\"\n"); lf_printf(file, "\n"); lf_printf(file, "#ifdef HAVE_STDLIB_H\n"); lf_printf(file, "#include <stdlib.h>\n"); lf_printf(file, "#endif\n"); lf_printf(file, "\n"); for(insn_ptr = model_data; insn_ptr; insn_ptr = insn_ptr->next) { model_c_or_h_data(table, file, insn_ptr->file_entry); } for(insn_ptr = model_static; insn_ptr; insn_ptr = insn_ptr->next) { model_c_or_h_function(table, file, insn_ptr->file_entry, "/*h*/STATIC"); } for(insn_ptr = model_internal; insn_ptr; insn_ptr = insn_ptr->next) { model_c_or_h_function(table, file, insn_ptr->file_entry, "STATIC_INLINE_MODEL"); } for(insn_ptr = model_static; insn_ptr; insn_ptr = insn_ptr->next) { model_c_function(table, file, insn_ptr->file_entry, "/*c*/STATIC"); } for(insn_ptr = model_internal; insn_ptr; insn_ptr = insn_ptr->next) { model_c_function(table, file, insn_ptr->file_entry, "STATIC_INLINE_MODEL"); } for(insn_ptr = model_functions; insn_ptr; insn_ptr = insn_ptr->next) { model_c_function(table, file, insn_ptr->file_entry, "INLINE_MODEL"); name = insn_ptr->file_entry->fields[function_name]; if (strcmp (name, "model_create") == 0) model_create_p = 1; else if (strcmp (name, "model_init") == 0) model_init_p = 1; else if (strcmp (name, "model_halt") == 0) model_halt_p = 1; else if (strcmp (name, "model_mon_info") == 0) model_mon_info_p = 1; else if (strcmp (name, "model_mon_info_free") == 0) model_mon_info_free_p = 1; } if (!model_create_p) { lf_print_function_type(file, "model_data *", "INLINE_MODEL", "\n"); lf_printf(file, "model_create(sim_cpu *cpu)\n"); lf_printf(file, "{\n"); lf_printf(file, " return (model_data *)0;\n"); lf_printf(file, "}\n"); lf_printf(file, "\n"); } if (!model_init_p) { lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); lf_printf(file, "model_init(model_data *model_ptr)\n"); lf_printf(file, "{\n"); lf_printf(file, "}\n"); lf_printf(file, "\n"); } if (!model_halt_p) { lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); lf_printf(file, "model_halt(model_data *model_ptr)\n"); lf_printf(file, "{\n"); lf_printf(file, "}\n"); lf_printf(file, "\n"); } if (!model_mon_info_p) { lf_print_function_type(file, "model_print *", "INLINE_MODEL", "\n"); lf_printf(file, "model_mon_info(model_data *model_ptr)\n"); lf_printf(file, "{\n"); lf_printf(file, " return (model_print *)0;\n"); lf_printf(file, "}\n"); lf_printf(file, "\n"); } if (!model_mon_info_free_p) { lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); lf_printf(file, "model_mon_info_free(model_data *model_ptr,\n"); lf_printf(file, " model_print *info_ptr)\n"); lf_printf(file, "{\n"); lf_printf(file, "}\n"); lf_printf(file, "\n"); } lf_printf(file, "/* Insn functional unit info */\n"); for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) { model_c_passed_data data; lf_printf(file, "static const model_time model_time_%s[] = {\n", model_ptr->name); data.file = file; data.model_ptr = model_ptr; insn_table_traverse_insn(table, NULL, (void *)&data, model_c_insn); lf_printf(file, "};\n"); lf_printf(file, "\n"); lf_printf(file, "\f\n"); } lf_printf(file, "#ifndef _INLINE_C_\n"); lf_printf(file, "const model_time *const model_time_mapping[ (int)nr_models ] = {\n"); lf_printf(file, " (const model_time *const)0,\n"); for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) { lf_printf(file, " model_time_%s,\n", model_ptr->name); } lf_printf(file, "};\n"); lf_printf(file, "#endif\n"); lf_printf(file, "\n"); lf_printf(file, "\f\n"); lf_printf(file, "/* map model enumeration into printable string */\n"); lf_printf(file, "#ifndef _INLINE_C_\n"); lf_printf(file, "const char *model_name[ (int)nr_models ] = {\n"); lf_printf(file, " \"NONE\",\n"); for (model_ptr = models; model_ptr; model_ptr = model_ptr->next) { lf_printf(file, " \"%s\",\n", model_ptr->printable_name); } lf_printf(file, "};\n"); lf_printf(file, "#endif\n"); lf_printf(file, "\n"); lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); lf_printf(file, "model_set(const char *name)\n"); lf_printf(file, "{\n"); if (models) { lf_printf(file, " model_enum model;\n"); lf_printf(file, " for(model = MODEL_%s; model < nr_models; model++) {\n", models->name); lf_printf(file, " if(strcmp(name, model_name[model]) == 0) {\n"); lf_printf(file, " current_model = model;\n"); lf_printf(file, " return;\n"); lf_printf(file, " }\n"); lf_printf(file, " }\n"); lf_printf(file, "\n"); lf_printf(file, " error(\"Unknown model '%%s', Models which are known are:%%s\n\",\n"); lf_printf(file, " name,\n"); lf_printf(file, " \""); for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) { lf_printf(file, "\\n\\t%s", model_ptr->printable_name); } lf_printf(file, "\");\n"); } else { lf_printf(file, " error(\"No models are currently known about\");\n"); } lf_printf(file, "}\n"); }
static void print_run_body (lf *file, gen_entry *table) { /* Output the function to execute real code: Unfortunatly, there are multiple cases to consider vis: <icache> X <smp> Consequently this function is written in multiple different ways */ lf_printf (file, "{\n"); lf_indent (file, +2); if (!options.gen.smp) { lf_printf (file, "%sinstruction_address cia;\n", options.module.global.prefix.l); } lf_printf (file, "int current_cpu = next_cpu_nr;\n"); if (options.gen.icache) { lf_printf (file, "/* flush the icache of a possible break insn */\n"); lf_printf (file, "{\n"); lf_printf (file, " int cpu_nr;\n"); lf_printf (file, " for (cpu_nr = 0; cpu_nr < nr_cpus; cpu_nr++)\n"); lf_printf (file, " cpu_flush_icache (STATE_CPU (sd, cpu_nr));\n"); lf_printf (file, "}\n"); } if (!options.gen.smp) { lf_putstr (file, "\ /* CASE 1: NO SMP (with or with out instruction cache).\n\ \n\ In this case, we can take advantage of the fact that the current\n\ instruction address (CIA) does not need to be read from / written to\n\ the CPU object after the execution of an instruction.\n\ \n\ Instead, CIA is only saved when the main loop exits. This occures\n\ when either sim_engine_halt or sim_engine_restart is called. Both of\n\ these functions save the current instruction address before halting /\n\ restarting the simulator.\n\ \n\ As a variation, there may also be support for an instruction cracking\n\ cache. */\n\ \n\ "); lf_putstr (file, "\n"); lf_putstr (file, "/* prime the main loop */\n"); lf_putstr (file, "SIM_ASSERT (current_cpu == 0);\n"); lf_putstr (file, "SIM_ASSERT (nr_cpus == 1);\n"); lf_putstr (file, "cia = CIA_GET (CPU);\n"); lf_putstr (file, "\n"); lf_putstr (file, "while (1)\n"); lf_putstr (file, " {\n"); lf_indent (file, +4); lf_printf (file, "%sinstruction_address nia;\n", options.module.global.prefix.l); lf_printf (file, "\n"); if (!options.gen.icache) { lf_printf (file, "%sinstruction_word instruction_0 = IMEM%d (cia);\n", options.module.global.prefix.l, options.insn_bit_size); print_engine_issue_prefix_hook (file); print_idecode_body (file, table, "nia = "); print_engine_issue_postfix_hook (file); } else { lf_putstr (file, "idecode_cache *cache_entry =\n"); lf_putstr (file, " cpu_icache_entry (cpu, cia);\n"); lf_putstr (file, "if (cache_entry->address == cia)\n"); lf_putstr (file, " {\n"); lf_indent (file, -4); lf_putstr (file, "/* cache hit */\n"); lf_putstr (file, "idecode_semantic *const semantic = cache_entry->semantic;\n"); lf_putstr (file, "cia = semantic (cpu, cache_entry, cia);\n"); /* tail */ lf_indent (file, -4); lf_putstr (file, " }\n"); lf_putstr (file, "else\n"); lf_putstr (file, " {\n"); lf_indent (file, +4); lf_putstr (file, "/* cache miss */\n"); if (!options.gen.semantic_icache) { lf_putstr (file, "idecode_semantic *semantic;\n"); } lf_printf (file, "instruction_word instruction = IMEM%d (cia);\n", options.insn_bit_size); lf_putstr (file, "if (WITH_MON != 0)\n"); lf_putstr (file, " mon_event (mon_event_icache_miss, cpu, cia);\n"); if (options.gen.semantic_icache) { lf_putstr (file, "{\n"); lf_indent (file, +2); print_engine_issue_prefix_hook (file); print_idecode_body (file, table, "nia ="); print_engine_issue_postfix_hook (file); lf_indent (file, -2); lf_putstr (file, "}\n"); } else { print_engine_issue_prefix_hook (file); print_idecode_body (file, table, "semantic ="); lf_putstr (file, "nia = semantic (cpu, cache_entry, cia);\n"); print_engine_issue_postfix_hook (file); } lf_indent (file, -4); lf_putstr (file, " }\n"); } /* update the cpu if necessary */ switch (options.gen.nia) { case nia_is_cia_plus_one: lf_printf (file, "\n"); lf_printf (file, "/* Update the instruction address */\n"); lf_printf (file, "cia = nia;\n"); break; case nia_is_void: case nia_is_invalid: ERROR ("engine gen when NIA complex"); } /* events */ lf_putstr (file, "\n"); lf_putstr (file, "/* process any events */\n"); lf_putstr (file, "if (sim_events_tick (sd))\n"); lf_putstr (file, " {\n"); lf_putstr (file, " CIA_SET (CPU, cia);\n"); lf_putstr (file, " sim_events_process (sd);\n"); lf_putstr (file, " cia = CIA_GET (CPU);\n"); lf_putstr (file, " }\n"); lf_indent (file, -4); lf_printf (file, " }\n"); }
void print_include (lf *file, igen_module module) { lf_printf (file, "#include \"%s%s.h\"\n", module.prefix.l, module.suffix.l); }
static void gen_run_c (lf *file, gen_table *gen) { gen_list *entry; lf_printf (file, "#include \"sim-main.h\"\n"); lf_printf (file, "#include \"engine.h\"\n"); lf_printf (file, "#include \"idecode.h\"\n"); lf_printf (file, "#include \"bfd.h\"\n"); lf_printf (file, "\n"); if (options.gen.multi_sim) { print_idecode_issue_function_header (file, NULL, is_function_variable, 1); lf_printf (file, "\n"); print_engine_run_function_header (file, NULL, is_function_variable); lf_printf (file, "\n"); } lf_printf (file, "void\n"); lf_printf (file, "sim_engine_run (SIM_DESC sd,\n"); lf_printf (file, " int next_cpu_nr,\n"); lf_printf (file, " int nr_cpus,\n"); lf_printf (file, " int siggnal)\n"); lf_printf (file, "{\n"); lf_indent (file, +2); if (options.gen.multi_sim) { lf_printf (file, "int mach;\n"); lf_printf (file, "if (STATE_ARCHITECTURE (sd) == NULL)\n"); lf_printf (file, " mach = 0;\n"); lf_printf (file, "else\n"); lf_printf (file, " mach = STATE_ARCHITECTURE (sd)->mach;\n"); lf_printf (file, "switch (mach)\n"); lf_printf (file, " {\n"); lf_indent (file, +2); for (entry = gen->tables; entry != NULL; entry = entry->next) { if (options.gen.default_model != NULL && (strcmp (entry->model->name, options.gen.default_model) == 0 || strcmp (entry->model->full_name, options.gen.default_model) == 0)) lf_printf (file, "default:\n"); lf_printf (file, "case bfd_mach_%s:\n", entry->model->full_name); lf_indent (file, +2); print_function_name (file, "issue", NULL, /* format name */ NULL, /* NO processor */ NULL, /* expanded bits */ function_name_prefix_idecode); lf_printf (file, " = "); print_function_name (file, "issue", NULL, /* format name */ entry->model->name, NULL, /* expanded bits */ function_name_prefix_idecode); lf_printf (file, ";\n"); print_function_name (file, "run", NULL, /* format name */ NULL, /* NO processor */ NULL, /* expanded bits */ function_name_prefix_engine); lf_printf (file, " = "); print_function_name (file, "run", NULL, /* format name */ entry->model->name, NULL, /* expanded bits */ function_name_prefix_engine); lf_printf (file, ";\n"); lf_printf (file, "break;\n"); lf_indent (file, -2); } if (options.gen.default_model == NULL) { lf_printf (file, "default:\n"); lf_indent (file, +2); lf_printf (file, "sim_engine_abort (sd, NULL, NULL_CIA,\n"); lf_printf (file, " \"sim_engine_run - unknown machine\");\n"); lf_printf (file, "break;\n"); lf_indent (file, -2); } lf_indent (file, -2); lf_printf (file, " }\n"); } print_function_name (file, "run", NULL, /* format name */ NULL, /* NO processor */ NULL, /* expanded bits */ function_name_prefix_engine); lf_printf (file, " (sd, next_cpu_nr, nr_cpus, siggnal);\n"); lf_indent (file, -2); lf_printf (file, "}\n"); }
void print_itrace (lf *file, insn_entry *insn, int idecode) { /* NB: Here we escape each EOLN. This is so that the the compiler treats a trace function call as a single line. Consequently any errors in the line are refered back to the same igen assembler source line */ const char *phase = (idecode) ? "DECODE" : "INSN"; lf_printf (file, "\n"); lf_indent_suppress (file); lf_printf (file, "#if defined (WITH_TRACE)\n"); lf_printf (file, "/* generate a trace prefix if any tracing enabled */\n"); lf_printf (file, "if (TRACE_ANY_P (CPU))\n"); lf_printf (file, " {\n"); lf_indent (file, +4); { if (insn->mnemonics != NULL) { insn_mnemonic_entry *assembler = insn->mnemonics; int is_first = 1; do { if (assembler->condition != NULL) { int indent; lf_printf (file, "%sif (%s)\n", is_first ? "" : "else ", assembler->condition); lf_indent (file, +2); lf_print__line_ref (file, assembler->line); indent = print_itrace_prefix (file); print_itrace_format (file, assembler); lf_print__internal_ref (file); lf_indent (file, -indent); lf_indent (file, -2); if (assembler->next == NULL) error (assembler->line, "Missing final unconditional assembler\n"); } else { int indent; if (!is_first) { lf_printf (file, "else\n"); lf_indent (file, +2); } lf_print__line_ref (file, assembler->line); indent = print_itrace_prefix (file); print_itrace_format (file, assembler); lf_print__internal_ref (file); lf_indent (file, -indent); if (!is_first) lf_indent (file, -2); if (assembler->next != NULL) error (assembler->line, "Unconditional assembler is not last\n"); } is_first = 0; assembler = assembler->next; } while (assembler != NULL); } else { int indent; lf_indent (file, +2); lf_print__line_ref (file, insn->line); indent = print_itrace_prefix (file); lf_printf (file, "%%s\", \\\n"); lf_printf (file, "itable[MY_INDEX].name);\n"); lf_print__internal_ref (file); lf_indent (file, -indent); lf_indent (file, -2); } lf_printf (file, "/* trace the instruction execution if enabled */\n"); lf_printf (file, "if (TRACE_%s_P (CPU))\n", phase); lf_printf (file, " trace_generic (SD, CPU, TRACE_%s_IDX, \" %%s\", itable[MY_INDEX].name);\n", phase); } lf_indent (file, -4); lf_printf (file, " }\n"); lf_indent_suppress (file); lf_printf (file, "#endif\n"); }
static void print_itrace_format (lf *file, insn_mnemonic_entry *assembler) { /* pass=1 is fmt string; pass=2 is arguments */ int pass; /* print the format string */ for (pass = 1; pass <= 2; pass++) { const char *chp = assembler->format; chp++; /* skip the leading quote */ /* write out the format/args */ while (*chp != '\0') { if (chp[0] == '\\' && (chp[1] == '<' || chp[1] == '>')) { if (pass == 1) lf_putchr (file, chp[1]); chp += 2; } else if (chp[0] == '<' || chp[0] == '%') { /* parse [ "%" ... ] "<" [ func "#" ] param ">" */ const char *fmt; const char *func; int strlen_func; const char *param; int strlen_param; /* the "%" ... "<" format */ fmt = chp; while (chp[0] != '<' && chp[0] != '\0') chp++; if (chp[0] != '<') error (assembler->line, "Missing `<' after `%%'\n"); chp++; /* [ "func" # ] OR "param" */ func = chp; param = chp; while (chp[0] != '>' && chp[0] != '#' && chp[0] != '\0') chp++; strlen_func = chp - func; if (chp[0] == '#') { chp++; param = chp; while (chp[0] != '>' && chp[0] != '\0') chp++; } strlen_param = chp - param; if (chp[0] != '>') error (assembler->line, "Missing closing `>' in assembler string\n"); chp++; /* now process it */ if (pass == 2) lf_printf (file, ", \\\n"); if (strncmp (fmt, "<", 1) == 0) /* implicit long int format */ { if (pass == 1) lf_printf (file, "%%ld"); else { lf_printf (file, "(long) "); lf_write (file, param, strlen_param); } } else if (strncmp (fmt, "%<", 2) == 0) /* explicit format */ { if (pass == 1) lf_printf (file, "%%"); else lf_write (file, param, strlen_param); } else if (strncmp (fmt, "%s<", 3) == 0) /* string format */ { if (pass == 1) lf_printf (file, "%%s"); else { lf_printf (file, "%sstr_", options.module.global.prefix.l); lf_write (file, func, strlen_func); lf_printf (file, " (SD_, "); lf_write (file, param, strlen_param); lf_printf (file, ")"); } } else if (strncmp (fmt, "%lx<", 4) == 0) /* simple hex */ { if (pass == 1) lf_printf (file, "%%lx"); else { lf_printf (file, "(unsigned long) "); lf_write (file, param, strlen_param); } } else if (strncmp (fmt, "%08lx<", 6) == 0) /* simple hex */ { if (pass == 1) lf_printf (file, "%%08lx"); else { lf_printf (file, "(unsigned long) "); lf_write (file, param, strlen_param); } } else error (assembler->line, "Unknown assembler string format\n"); } else { if (pass == 1) lf_putchr (file, chp[0]); chp += 1; } } } lf_printf (file, ");\n"); }
void print_my_defines (lf *file, const char *basename, const char *format_name, opcode_bits *expanded_bits) { /* #define MY_INDEX xxxxx */ lf_indent_suppress (file); lf_printf (file, "#undef MY_INDEX\n"); lf_indent_suppress (file); lf_printf (file, "#define MY_INDEX "); print_function_name (file, basename, format_name, NULL, NULL, function_name_prefix_itable); lf_printf (file, "\n"); /* #define MY_PREFIX xxxxxx */ lf_indent_suppress (file); lf_printf (file, "#undef "); print_function_name (file, basename, format_name, NULL, expanded_bits, function_name_prefix_none); lf_printf (file, "\n"); lf_indent_suppress (file); lf_printf (file, "#undef MY_PREFIX\n"); lf_indent_suppress (file); lf_printf (file, "#define MY_PREFIX "); print_function_name (file, basename, format_name, NULL, expanded_bits, function_name_prefix_none); lf_printf (file, "\n"); /* #define MY_NAME xxxxxx */ lf_indent_suppress (file); lf_indent_suppress (file); lf_printf (file, "#undef MY_NAME\n"); lf_indent_suppress (file); lf_printf (file, "#define MY_NAME \""); print_function_name (file, basename, format_name, NULL, expanded_bits, function_name_prefix_none); lf_printf (file, "\"\n"); }
static void print_icache_extraction (lf *file, const char *format_name, cache_entry_type cache_type, const char *entry_name, const char *entry_type, const char *entry_expression, char *single_insn_field, line_ref *line, insn_field_entry *cur_field, opcode_bits *expanded_bits, icache_decl_type what_to_declare, icache_body_type what_to_do) { const char *expression; opcode_bits *bits; char *reason; ASSERT (format_name != NULL); ASSERT (entry_name != NULL); /* figure out exactly what should be going on here */ switch (cache_type) { case scratch_value: if ((what_to_do & put_values_in_icache) || what_to_do == do_not_use_icache) { reason = "scratch"; what_to_do = do_not_use_icache; } else return; break; case compute_value: if ((what_to_do & get_values_from_icache) || what_to_do == do_not_use_icache) { reason = "compute"; what_to_do = do_not_use_icache; } else return; break; case cache_value: if ((what_to_declare != undef_variables) || !(what_to_do & put_values_in_icache)) { reason = "cache"; what_to_declare = ((what_to_do & put_values_in_icache) ? declare_variables : what_to_declare); } else return; break; default: abort (); /* Bad switch. */ } /* For the type, default to a simple unsigned */ if (entry_type == NULL || strlen (entry_type) == 0) entry_type = "unsigned"; /* look through the set of expanded sub fields to see if this field has been given a constant value */ for (bits = expanded_bits; bits != NULL; bits = bits->next) { if (bits->field == cur_field) break; } /* Define a storage area for the cache element */ switch (what_to_declare) { case undef_variables: /* We've finished with the #define value - destory it */ lf_indent_suppress (file); lf_printf (file, "#undef %s\n", entry_name); return; case define_variables: /* Using direct access for this entry, clear any prior definition, then define it */ lf_indent_suppress (file); lf_printf (file, "#undef %s\n", entry_name); /* Don't type cast pointer types! */ lf_indent_suppress (file); if (strchr (entry_type, '*') != NULL) lf_printf (file, "#define %s (", entry_name); else lf_printf (file, "#define %s ((%s) ", entry_name, entry_type); break; case declare_variables: /* using variables to define the value */ if (line != NULL) lf_print__line_ref (file, line); lf_printf (file, "%s const %s UNUSED = ", entry_type, entry_name); break; } /* define a value for that storage area as determined by what is in the cache */ if (bits != NULL && single_insn_field != NULL && strcmp (entry_name, single_insn_field) == 0 && strcmp (entry_name, cur_field->val_string) == 0 && ((bits->opcode->is_boolean && bits->value == 0) || (!bits->opcode->is_boolean))) { /* The cache rule is specifying what to do with a simple instruction field. Because of instruction expansion, the field is either a constant value or equal to the specified constant (boolean comparison). (The latter indicated by bits->value == 0). The case of a field not being equal to the specified boolean value is handled later. */ expression = "constant field"; ASSERT (bits->field == cur_field); if (bits->opcode->is_boolean) { ASSERT (bits->value == 0); lf_printf (file, "%d", bits->opcode->boolean_constant); } else if (bits->opcode->last < bits->field->last) { lf_printf (file, "%d", bits->value << (bits->field->last - bits->opcode->last)); } else { lf_printf (file, "%d", bits->value); } } else if (bits != NULL && single_insn_field != NULL && strncmp (entry_name, single_insn_field, strlen (single_insn_field)) == 0 && strncmp (entry_name + strlen (single_insn_field), "_is_", strlen ("_is_")) == 0 && ((bits->opcode->is_boolean && ((unsigned) atol (entry_name + strlen (single_insn_field) + strlen ("_is_")) == bits->opcode->boolean_constant)) || (!bits->opcode->is_boolean))) { /* The cache rule defines an entry for the comparison between a single instruction field and a constant. The value of the comparison in someway matches that of the opcode field that was made constant through expansion. */ expression = "constant compare"; if (bits->opcode->is_boolean) { lf_printf (file, "%d /* %s == %d */", bits->value == 0, single_insn_field, bits->opcode->boolean_constant); } else if (bits->opcode->last < bits->field->last) { lf_printf (file, "%d /* %s == %d */", (atol (entry_name + strlen (single_insn_field) + strlen ("_is_")) == (bits-> value << (bits->field->last - bits->opcode->last))), single_insn_field, (bits-> value << (bits->field->last - bits->opcode->last))); } else { lf_printf (file, "%d /* %s == %d */", (atol (entry_name + strlen (single_insn_field) + strlen ("_is_")) == bits->value), single_insn_field, bits->value); } } else { /* put the field in the local variable, possibly also enter it into the cache */ expression = "extraction"; /* handle the cache */ if ((what_to_do & get_values_from_icache) || (what_to_do & put_values_in_icache)) { lf_printf (file, "cache_entry->crack.%s.%s", format_name, entry_name); if (what_to_do & put_values_in_icache) /* also put it in the cache? */ { lf_printf (file, " = "); } } if ((what_to_do & put_values_in_icache) || what_to_do == do_not_use_icache) { if (cur_field != NULL) { if (entry_expression != NULL && strlen (entry_expression) > 0) error (line, "Instruction field entry with nonempty expression\n"); if (cur_field->first == 0 && cur_field->last == options.insn_bit_size - 1) lf_printf (file, "(instruction_%d)", cur_field->word_nr); else if (cur_field->last == options.insn_bit_size - 1) lf_printf (file, "MASKED%d (instruction_%d, %d, %d)", options.insn_bit_size, cur_field->word_nr, i2target (options.hi_bit_nr, cur_field->first), i2target (options.hi_bit_nr, cur_field->last)); else lf_printf (file, "EXTRACTED%d (instruction_%d, %d, %d)", options.insn_bit_size, cur_field->word_nr, i2target (options.hi_bit_nr, cur_field->first), i2target (options.hi_bit_nr, cur_field->last)); } else { lf_printf (file, "%s", entry_expression); } } } switch (what_to_declare) { case define_variables: lf_printf (file, ")"); break; case undef_variables: break; case declare_variables: lf_printf (file, ";"); break; } ASSERT (reason != NULL && expression != NULL); lf_printf (file, " /* %s - %s */\n", reason, expression); }
void gen_model_h(insn_table *table, lf *file) { insn *insn_ptr; model *model_ptr; insn *macro; char *name; int model_create_p = 0; int model_init_p = 0; int model_halt_p = 0; int model_mon_info_p = 0; int model_mon_info_free_p = 0; for(macro = model_macros; macro; macro = macro->next) { model_c_or_h_data(table, file, macro->file_entry); } lf_printf(file, "typedef enum _model_enum {\n"); lf_printf(file, " MODEL_NONE,\n"); for (model_ptr = models; model_ptr; model_ptr = model_ptr->next) { lf_printf(file, " MODEL_%s,\n", model_ptr->name); } lf_printf(file, " nr_models\n"); lf_printf(file, "} model_enum;\n"); lf_printf(file, "\n"); lf_printf(file, "#define DEFAULT_MODEL MODEL_%s\n", (models) ? models->name : "NONE"); lf_printf(file, "\n"); lf_printf(file, "typedef struct _model_data model_data;\n"); lf_printf(file, "typedef struct _model_time model_time;\n"); lf_printf(file, "\n"); lf_printf(file, "extern model_enum current_model;\n"); lf_printf(file, "extern const char *model_name[ (int)nr_models ];\n"); lf_printf(file, "extern const char *const *const model_func_unit_name[ (int)nr_models ];\n"); lf_printf(file, "extern const model_time *const model_time_mapping[ (int)nr_models ];\n"); lf_printf(file, "\n"); for(insn_ptr = model_functions; insn_ptr; insn_ptr = insn_ptr->next) { model_c_or_h_function(table, file, insn_ptr->file_entry, "INLINE_MODEL"); name = insn_ptr->file_entry->fields[function_name]; if (strcmp (name, "model_create") == 0) model_create_p = 1; else if (strcmp (name, "model_init") == 0) model_init_p = 1; else if (strcmp (name, "model_halt") == 0) model_halt_p = 1; else if (strcmp (name, "model_mon_info") == 0) model_mon_info_p = 1; else if (strcmp (name, "model_mon_info_free") == 0) model_mon_info_free_p = 1; } if (!model_create_p) { lf_print_function_type(file, "model_data *", "INLINE_MODEL", " "); lf_printf(file, "model_create\n"); lf_printf(file, "(sim_cpu *cpu);\n"); lf_printf(file, "\n"); } if (!model_init_p) { lf_print_function_type(file, "void", "INLINE_MODEL", " "); lf_printf(file, "model_init\n"); lf_printf(file, "(model_data *model_ptr);\n"); lf_printf(file, "\n"); } if (!model_halt_p) { lf_print_function_type(file, "void", "INLINE_MODEL", " "); lf_printf(file, "model_halt\n"); lf_printf(file, "(model_data *model_ptr);\n"); lf_printf(file, "\n"); } if (!model_mon_info_p) { lf_print_function_type(file, "model_print *", "INLINE_MODEL", " "); lf_printf(file, "model_mon_info\n"); lf_printf(file, "(model_data *model_ptr);\n"); lf_printf(file, "\n"); } if (!model_mon_info_free_p) { lf_print_function_type(file, "void", "INLINE_MODEL", " "); lf_printf(file, "model_mon_info_free\n"); lf_printf(file, "(model_data *model_ptr,\n"); lf_printf(file, " model_print *info_ptr);\n"); lf_printf(file, "\n"); } lf_print_function_type(file, "void", "INLINE_MODEL", " "); lf_printf(file, "model_set\n"); lf_printf(file, "(const char *name);\n"); }
extern void gen_support_h (lf *file, insn_table *table) { /* output the definition of `SD_' */ if (options.gen.smp) { lf_printf (file, "#define SD CPU_STATE (cpu)\n"); lf_printf (file, "#define CPU cpu\n"); lf_printf (file, "#define CPU_ cpu\n"); } else { lf_printf (file, "#define SD sd\n"); lf_printf (file, "#define CPU (STATE_CPU (sd, 0))\n"); lf_printf (file, "#define CPU_ sd\n"); } lf_printf (file, "#define CIA_ cia\n"); if (options.gen.delayed_branch) { lf_printf (file, "#define CIA cia.ip\n"); lf_printf (file, "/* #define NIA nia.dp -- do not define, ambigious */\n"); } else { lf_printf (file, "#define CIA cia\n"); lf_printf (file, "#define NIA nia\n"); } lf_printf (file, "\n"); lf_printf (file, "#define SD_ CPU_, CIA_, MY_INDEX\n"); lf_printf (file, "#define _SD SD_ /* deprecated */\n"); lf_printf (file, "\n"); /* Map <PREFIX>_xxxx onto the shorter xxxx for the following names: instruction_word idecode_issue semantic_illegal Map defined here as name space problems are created when the name is defined in idecode.h */ if (strcmp (options.module.idecode.prefix.l, "") != 0) { lf_indent_suppress (file); lf_printf (file, "#define %s %s%s\n", "instruction_word", options.module.idecode.prefix.l, "instruction_word"); lf_printf (file, "\n"); lf_indent_suppress (file); lf_printf (file, "#define %s %s%s\n", "idecode_issue", options.module.idecode.prefix.l, "idecode_issue"); lf_printf (file, "\n"); lf_indent_suppress (file); lf_printf (file, "#define %s %s%s\n", "semantic_illegal", options.module.idecode.prefix.l, "semantic_illegal"); lf_printf (file, "\n"); } /* output a declaration for all functions */ function_entry_traverse (file, table->functions, support_h_function, NULL); lf_printf (file, "\n"); lf_printf (file, "#if defined(SUPPORT_INLINE)\n"); lf_printf (file, "# if ((SUPPORT_INLINE & INCLUDE_MODULE)\\\n"); lf_printf (file, " && (SUPPORT_INLINE & INCLUDED_BY_MODULE))\n"); lf_printf (file, "# include \"%ssupport.c\"\n", options.module.support.prefix.l); lf_printf (file, "# endif\n"); lf_printf (file, "#endif\n"); }
extern void gen_itable_h (lf *file, insn_table *isa) { itable_info *info = ZALLOC (itable_info); /* output an enumerated type for each instruction */ lf_printf (file, "typedef enum {\n"); insn_table_traverse_insn (file, isa, itable_h_insn, info); lf_printf (file, " nr_%sitable_entries,\n", options.module.itable.prefix.l); lf_printf (file, "} %sitable_index;\n", options.module.itable.prefix.l); lf_printf (file, "\n"); /* output an enumeration type for each flag */ itable_print_enum (file, isa->flags, "flag"); lf_printf (file, "extern const char *%sitable_flag_names[];\n", options.module.itable.prefix.l); lf_printf (file, "\n"); /* output an enumeration of all the possible options */ itable_print_enum (file, isa->options, "option"); lf_printf (file, "extern const char *%sitable_option_names[];\n", options.module.itable.prefix.l); lf_printf (file, "\n"); /* output an enumeration of all the processor models */ itable_print_enum (file, isa->model->processors, "processor"); lf_printf (file, "extern const char *%sitable_processor_names[];\n", options.module.itable.prefix.l); lf_printf (file, "\n"); /* output the table that contains the actual instruction info */ lf_printf (file, "typedef struct _%sitable_instruction_info {\n", options.module.itable.prefix.l); lf_printf (file, " %sitable_index nr;\n", options.module.itable.prefix.l); lf_printf (file, " char *format;\n"); lf_printf (file, " char *form;\n"); lf_printf (file, " char *flags;\n"); /* nr_itable_* may be zero, so we add 1 to avoid an illegal zero-sized array. */ lf_printf (file, " char flag[nr_%sitable_flags + 1];\n", options.module.itable.prefix.l); lf_printf (file, " char *options;\n"); lf_printf (file, " char option[nr_%sitable_options + 1];\n", options.module.itable.prefix.l); lf_printf (file, " char *processors;\n"); lf_printf (file, " char processor[nr_%sitable_processors + 1];\n", options.module.itable.prefix.l); lf_printf (file, " char *name;\n"); lf_printf (file, " char *file;\n"); lf_printf (file, " int line_nr;\n"); lf_printf (file, "} %sitable_info;\n", options.module.itable.prefix.l); lf_printf (file, "\n"); lf_printf (file, "extern %sitable_info %sitable[nr_%sitable_entries];\n", options.module.itable.prefix.l, options.module.itable.prefix.l, options.module.itable.prefix.l); if (strlen (options.module.itable.prefix.l) > 0) { lf_indent_suppress (file); lf_printf (file, "#define itable %sitable\n", options.module.itable.prefix.l); } lf_printf (file, "\n"); /* output an enum defining the max size of various itable members */ lf_printf (file, "enum {\n"); lf_printf (file, " sizeof_%sitable_form = %d,\n", options.module.itable.prefix.l, info->sizeof_form); lf_printf (file, " sizeof_%sitable_name = %d,\n", options.module.itable.prefix.l, info->sizeof_name); lf_printf (file, " sizeof_%sitable_file = %d,\n", options.module.itable.prefix.l, info->sizeof_file); lf_printf (file, "};\n"); }
void print_icache_body(lf *file, insn *instruction, insn_bits *expanded_bits, cache_table *cache_rules, icache_decl_type what_to_declare, icache_body_type what_to_do) { insn_field *cur_field; /* extract instruction fields */ lf_printf(file, "/* extraction: %s ", instruction->file_entry->fields[insn_format]); switch (what_to_declare) { case define_variables: lf_printf(file, "#define"); break; case declare_variables: lf_printf(file, "declare"); break; case undef_variables: lf_printf(file, "#undef"); break; } lf_printf(file, " "); switch (what_to_do) { case get_values_from_icache: lf_printf(file, "get-values-from-icache"); break; case put_values_in_icache: lf_printf(file, "put-values-in-icache"); break; case both_values_and_icache: lf_printf(file, "get-values-from-icache|put-values-in-icache"); break; case do_not_use_icache: lf_printf(file, "do-not-use-icache"); break; } lf_printf(file, " */\n"); for (cur_field = instruction->fields->first; cur_field->first < insn_bit_size; cur_field = cur_field->next) { if (cur_field->is_string) { insn_bits *bits; int found_rule = 0; /* find any corresponding value */ for (bits = expanded_bits; bits != NULL; bits = bits->last) { if (bits->field == cur_field) break; } /* try the cache rule table for what to do */ { cache_table *cache_rule; for (cache_rule = cache_rules; cache_rule != NULL; cache_rule = cache_rule->next) { if (strcmp(cur_field->val_string, cache_rule->field_name) == 0) { found_rule = 1; if (cache_rule->type == scratch_value && ((what_to_do & put_values_in_icache) || what_to_do == do_not_use_icache)) print_icache_extraction(file, instruction, cache_rule->derived_name, cache_rule->type_def, cache_rule->expression, cache_rule->field_name, cache_rule->file_entry->file_name, cache_rule->file_entry->line_nr, cur_field, bits, what_to_declare, do_not_use_icache, "icache scratch"); else if (cache_rule->type == compute_value && ((what_to_do & get_values_from_icache) || what_to_do == do_not_use_icache)) print_icache_extraction(file, instruction, cache_rule->derived_name, cache_rule->type_def, cache_rule->expression, cache_rule->field_name, cache_rule->file_entry->file_name, cache_rule->file_entry->line_nr, cur_field, bits, what_to_declare, do_not_use_icache, "semantic compute"); else if (cache_rule->type == cache_value && ((what_to_declare != undef_variables) || !(what_to_do & put_values_in_icache))) print_icache_extraction(file, instruction, cache_rule->derived_name, cache_rule->type_def, cache_rule->expression, cache_rule->field_name, cache_rule->file_entry->file_name, cache_rule->file_entry->line_nr, cur_field, bits, ((what_to_do & put_values_in_icache) ? declare_variables : what_to_declare), what_to_do, "in icache"); } } } /* No rule at all, assume that this is needed in the semantic function (when values are extracted from the icache) and hence must be put into the cache */ if (found_rule == 0 && ((what_to_declare != undef_variables) || !(what_to_do & put_values_in_icache))) print_icache_extraction(file, instruction, cur_field->val_string, NULL, NULL, NULL, /* type, exp, orig */ instruction->file_entry->file_name, instruction->file_entry->line_nr, cur_field, bits, ((what_to_do & put_values_in_icache) ? declare_variables : what_to_declare), what_to_do, "default in icache"); /* any thing else ... */ } } lf_print__internal_reference(file); if ((code & generate_with_insn_in_icache)) { lf_printf(file, "\n"); print_icache_extraction(file, instruction, "insn", "instruction_word", "instruction", NULL, /* origin */ NULL, 0, /* file_name & line_nr */ NULL, NULL, what_to_declare, what_to_do, NULL); } }
int main (int argc, char **argv, char **envp) { cache_entry *cache_rules = NULL; lf_file_references file_references = lf_include_references; decode_table *decode_rules = NULL; insn_table *isa = NULL; gen_table *gen = NULL; char *real_file_name = NULL; int is_header = 0; int ch; lf *standard_out = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "igen"); INIT_OPTIONS (); if (argc == 1) { printf ("Usage:\n"); printf ("\n"); printf (" igen <config-opts> ... <input-opts>... <output-opts>...\n"); printf ("\n"); printf ("Config options:\n"); printf ("\n"); printf (" -B <bit-size>\n"); printf ("\t Set the number of bits in an instruction (depreciated).\n"); printf ("\t This option can now be set directly in the instruction table.\n"); printf ("\n"); printf (" -D <data-structure>\n"); printf ("\t Dump the specified data structure to stdout. Valid structures include:\n"); printf ("\t processor-names - list the names of all the processors (models)\n"); printf ("\n"); printf (" -F <filter-list>\n"); printf ("\t Filter out any instructions with a non-empty flags field that contains\n"); printf ("\t a flag not listed in the <filter-list>.\n"); printf ("\n"); printf (" -H <high-bit>\n"); printf ("\t Set the number of the high (most significant) instruction bit (depreciated).\n"); printf ("\t This option can now be set directly in the instruction table.\n"); printf ("\n"); printf (" -I <directory>\n"); printf ("\t Add <directory> to the list of directories searched when opening a file\n"); printf ("\n"); printf (" -M <model-list>\n"); printf ("\t Filter out any instructions that do not support at least one of the listed\n"); printf ("\t models (An instructions with no model information is considered to support\n"); printf ("\t all models.).\n"); printf ("\n"); printf (" -N <nr-cpus>\n"); printf ("\t Generate a simulator supporting <nr-cpus>\n"); printf ("\t Specify `-N 0' to disable generation of the SMP. Specifying `-N 1' will\n"); printf ("\t still generate an SMP enabled simulator but will only support one CPU.\n"); printf ("\n"); printf (" -T <mechanism>\n"); printf ("\t Override the decode mechanism specified by the decode rules\n"); printf ("\n"); printf (" -P <prefix>\n"); printf ("\t Prepend global names (except itable) with the string <prefix>.\n"); printf ("\t Specify -P <module>=<prefix> to set a specific <module>'s prefix.\n"); printf ("\n"); printf (" -S <suffix>\n"); printf ("\t Replace a global name (suffix) (except itable) with the string <suffix>.\n"); printf ("\t Specify -S <module>=<suffix> to change a specific <module>'s name (suffix).\n"); printf ("\n"); printf (" -Werror\n"); printf ("\t Make warnings errors\n"); printf (" -Wnodiscard\n"); printf ("\t Suppress warnings about discarded functions and instructions\n"); printf (" -Wnowidth\n"); printf ("\t Suppress warnings about instructions with invalid widths\n"); printf (" -Wnounimplemented\n"); printf ("\t Suppress warnings about unimplemented instructions\n"); printf ("\n"); printf (" -G [!]<gen-option>\n"); printf ("\t Any of the following options:\n"); printf ("\n"); printf ("\t decode-duplicate - Override the decode rules, forcing the duplication of\n"); printf ("\t semantic functions\n"); printf ("\t decode-combine - Combine any duplicated entries within a table\n"); printf ("\t decode-zero-reserved - Override the decode rules, forcing reserved bits to be\n"); printf ("\t treated as zero.\n"); printf ("\t decode-switch-is-goto - Overfide the padded-switch code type as a goto-switch\n"); printf ("\n"); printf ("\t gen-conditional-issue - conditionally issue each instruction\n"); printf ("\t gen-delayed-branch - need both cia and nia passed around\n"); printf ("\t gen-direct-access - use #defines to directly access values\n"); printf ("\t gen-zero-r<N> - arch assumes GPR(<N>) == 0, keep it that way\n"); printf ("\t gen-icache[=<N> - generate an instruction cracking cache of size <N>\n"); printf ("\t Default size is %d\n", options.gen.icache_size); printf ("\t gen-insn-in-icache - save original instruction when cracking\n"); printf ("\t gen-multi-sim[=MODEL] - generate multiple simulators - one per model\n"); printf ("\t If specified MODEL is made the default architecture.\n"); printf ("\t By default, a single simulator that will\n"); printf ("\t execute any instruction is generated\n"); printf ("\t gen-multi-word - generate code allowing for multi-word insns\n"); printf ("\t gen-semantic-icache - include semantic code in cracking functions\n"); printf ("\t gen-slot-verification - perform slot verification as part of decode\n"); printf ("\t gen-nia-invalid - NIA defaults to nia_invalid\n"); printf ("\t gen-nia-void - do not compute/return NIA\n"); printf ("\n"); printf ("\t trace-combine - report combined entries a rule application\n"); printf ("\t trace-entries - report entries after a rules application\n"); printf ("\t trace-rule-rejection - report each rule as rejected\n"); printf ("\t trace-rule-selection - report each rule as selected\n"); printf ("\t trace-insn-insertion - report each instruction as it is inserted into a decode table\n"); printf ("\t trace-rule-expansion - report each instruction as it is expanded (before insertion into a decode table)\n"); printf ("\t trace-all - enable all trace options\n"); printf ("\n"); printf ("\t field-widths - instruction formats specify widths (depreciated)\n"); printf ("\t By default, an instruction format specifies bit\n"); printf ("\t positions\n"); printf ("\t This option can now be set directly in the\n"); printf ("\t instruction table\n"); printf ("\t jumps - use jumps instead of function calls\n"); printf ("\t omit-line-numbers - do not include line number information in the output\n"); printf ("\n"); printf ("Input options:\n"); printf ("\n"); printf (" -k <cache-rules> (depreciated)\n"); printf (" -o <decode-rules>\n"); printf (" -i <instruction-table>\n"); printf ("\n"); printf ("Output options:\n"); printf ("\n"); printf (" -x Perform expansion (required)\n"); printf (" -n <real-name> Specify the real name of the next output file\n"); printf (" -h Generate the header (.h) file rather than the body (.c)\n"); printf (" -c <output-file> output icache\n"); printf (" -d <output-file> output idecode\n"); printf (" -e <output-file> output engine\n"); printf (" -f <output-file> output support functions\n"); printf (" -m <output-file> output model\n"); printf (" -r <output-file> output multi-sim run\n"); printf (" -s <output-file> output schematic\n"); printf (" -t <output-file> output itable\n"); } while ((ch = getopt(argc, argv, "B:D:F:G:H:I:M:N:P:T:W:o:k:i:n:hc:d:e:m:r:s:t:f:x")) != -1) { fprintf (stderr, " -%c ", ch); if (optarg) fprintf (stderr, "%s ", optarg); fprintf (stderr, "\\\n"); switch(ch) { case 'M': filter_parse (&options.model_filter, optarg); break; case 'D': if (strcmp (optarg, "processor-names")) { char *processor; for (processor = filter_next (options.model_filter, ""); processor != NULL; processor = filter_next (options.model_filter, processor)) lf_printf (standard_out, "%s\n", processor); } else error (NULL, "Unknown data structure %s, not dumped\n", optarg); break; case 'F': filter_parse (&options.flags_filter, optarg); break; case 'I': { table_include **dir = &options.include; while ((*dir) != NULL) dir = &(*dir)->next; (*dir) = ZALLOC (table_include); (*dir)->dir = strdup (optarg); } break; case 'B': options.insn_bit_size = a2i (optarg); if (options.insn_bit_size <= 0 || options.insn_bit_size > max_insn_bit_size) { error (NULL, "Instruction bitsize must be in range 1..%d\n", max_insn_bit_size); } if (options.hi_bit_nr != options.insn_bit_size - 1 && options.hi_bit_nr != 0) { error (NULL, "Conflict betweem hi-bit-nr and insn-bit-size\n"); } break; case 'H': options.hi_bit_nr = a2i (optarg); if (options.hi_bit_nr != options.insn_bit_size - 1 && options.hi_bit_nr != 0) { error (NULL, "Conflict between hi-bit-nr and insn-bit-size\n"); } break; case 'N': options.gen.smp = a2i (optarg); break; case 'P': case 'S': { igen_module *names; igen_name *name; char *chp; chp = strchr (optarg, '='); if (chp == NULL) { names = &options.module.global; chp = optarg; } else { chp = chp + 1; /* skip `=' */ names = NULL; if (strncmp (optarg, "global=", chp - optarg) == 0) { names = &options.module.global; } if (strncmp (optarg, "engine=", chp - optarg) == 0) { names = &options.module.engine; } if (strncmp (optarg, "icache=", chp - optarg) == 0) { names = &options.module.icache; } if (strncmp (optarg, "idecode=", chp - optarg) == 0) { names = &options.module.idecode; } if (strncmp (optarg, "itable=", chp - optarg) == 0) { names = &options.module.itable; } if (strncmp (optarg, "semantics=", chp - optarg) == 0) { names = &options.module.semantics; } if (strncmp (optarg, "support=", chp - optarg) == 0) { names = &options.module.support; } if (names == NULL) { error (NULL, "Prefix `%s' unreconized\n", optarg); } } switch (ch) { case 'P': name = &names->prefix; break; case 'S': name = &names->suffix; break; } name->u = strdup (chp); name->l = strdup (chp); chp = name->u; while (*chp) { if (islower(*chp)) *chp = toupper(*chp); chp++; } if (name == &options.module.global.prefix) { options.module.engine.prefix = options.module.global.prefix; options.module.icache.prefix = options.module.global.prefix; options.module.idecode.prefix = options.module.global.prefix; /* options.module.itable.prefix = options.module.global.prefix; */ options.module.semantics.prefix = options.module.global.prefix; options.module.support.prefix = options.module.global.prefix; } if (name == &options.module.global.suffix) { options.module.engine.suffix = options.module.global.suffix; options.module.icache.suffix = options.module.global.suffix; options.module.idecode.suffix = options.module.global.suffix; /* options.module.itable.suffix = options.module.global.suffix; */ options.module.semantics.suffix = options.module.global.suffix; options.module.support.suffix = options.module.global.suffix; } break; } case 'W': { if (strcmp (optarg, "error") == 0) options.warning = error; else if (strcmp (optarg, "nodiscard") == 0) options.warn.discard = 0; else if (strcmp (optarg, "discard") == 0) options.warn.discard = 1; else if (strcmp (optarg, "nowidth") == 0) options.warn.width = 0; else if (strcmp (optarg, "width") == 0) options.warn.width = 1; else if (strcmp (optarg, "nounimplemented") == 0) options.warn.unimplemented = 0; else if (strcmp (optarg, "unimplemented") == 0) options.warn.unimplemented = 1; else error (NULL, "Unknown -W argument `%s'\n", optarg); break; } case 'G': { int enable_p; char *argp; if (strncmp (optarg, "no-", strlen ("no-")) == 0) { argp = optarg + strlen ("no-"); enable_p = 0; } else if (strncmp (optarg, "!", strlen ("!")) == 0) { argp = optarg + strlen ("no-"); enable_p = 0; } else { argp = optarg; enable_p = 1; } if (strcmp (argp, "decode-duplicate") == 0) { options.decode.duplicate = enable_p; } else if (strcmp (argp, "decode-combine") == 0) { options.decode.combine = enable_p; } else if (strcmp (argp, "decode-zero-reserved") == 0) { options.decode.zero_reserved = enable_p; } else if (strcmp (argp, "gen-conditional-issue") == 0) { options.gen.conditional_issue = enable_p; } else if (strcmp (argp, "conditional-issue") == 0) { options.gen.conditional_issue = enable_p; options.warning (NULL, "Option conditional-issue replaced by gen-conditional-issue\n"); } else if (strcmp (argp, "gen-delayed-branch") == 0) { options.gen.delayed_branch = enable_p; } else if (strcmp (argp, "delayed-branch") == 0) { options.gen.delayed_branch = enable_p; options.warning (NULL, "Option delayed-branch replaced by gen-delayed-branch\n"); } else if (strcmp (argp, "gen-direct-access") == 0) { options.gen.direct_access = enable_p; } else if (strcmp (argp, "direct-access") == 0) { options.gen.direct_access = enable_p; options.warning (NULL, "Option direct-access replaced by gen-direct-access\n"); } else if (strncmp (argp, "gen-zero-r", strlen ("gen-zero-r")) == 0) { options.gen.zero_reg = enable_p; options.gen.zero_reg_nr = atoi (argp + strlen ("gen-zero-r")); } else if (strncmp (argp, "zero-r", strlen ("zero-r")) == 0) { options.gen.zero_reg = enable_p; options.gen.zero_reg_nr = atoi (argp + strlen ("zero-r")); options.warning (NULL, "Option zero-r<N> replaced by gen-zero-r<N>\n"); } else if (strncmp (argp, "gen-icache", strlen ("gen-icache")) == 0) { switch (argp[strlen ("gen-icache")]) { case '=': options.gen.icache_size = atoi (argp + strlen ("gen-icache") + 1); options.gen.icache = enable_p; break; case '\0': options.gen.icache = enable_p; break; default: error (NULL, "Expecting -Ggen-icache or -Ggen-icache=<N>\n"); } } else if (strcmp (argp, "gen-insn-in-icache") == 0) { options.gen.insn_in_icache = enable_p; } else if (strncmp (argp, "gen-multi-sim", strlen ("gen-multi-sim")) == 0) { char *arg = &argp[strlen ("gen-multi-sim")]; switch (arg[0]) { case '=': options.gen.multi_sim = enable_p; options.gen.default_model = arg + 1; if (! filter_is_member (options.model_filter, options.gen.default_model)) error (NULL, "multi-sim model %s unknown\n", options.gen.default_model); break; case '\0': options.gen.multi_sim = enable_p; options.gen.default_model = NULL; break; default: error (NULL, "Expecting -Ggen-multi-sim or -Ggen-multi-sim=<MODEL>\n"); break; } } else if (strcmp (argp, "gen-multi-word") == 0) { options.gen.multi_word = enable_p; } else if (strcmp (argp, "gen-semantic-icache") == 0) { options.gen.semantic_icache = enable_p; } else if (strcmp (argp, "gen-slot-verification") == 0) { options.gen.slot_verification = enable_p; } else if (strcmp (argp, "verify-slot") == 0) { options.gen.slot_verification = enable_p; options.warning (NULL, "Option verify-slot replaced by gen-slot-verification\n"); } else if (strcmp (argp, "gen-nia-invalid") == 0) { options.gen.nia = nia_is_invalid; } else if (strcmp (argp, "default-nia-minus-one") == 0) { options.gen.nia = nia_is_invalid; options.warning (NULL, "Option default-nia-minus-one replaced by gen-nia-invalid\n"); } else if (strcmp (argp, "gen-nia-void") == 0) { options.gen.nia = nia_is_void; } else if (strcmp (argp, "trace-all") == 0) { memset (&options.trace, enable_p, sizeof (options.trace)); } else if (strcmp (argp, "trace-combine") == 0) { options.trace.combine = enable_p; } else if (strcmp (argp, "trace-entries") == 0) { options.trace.entries = enable_p; } else if (strcmp (argp, "trace-rule-rejection") == 0) { options.trace.rule_rejection = enable_p; } else if (strcmp (argp, "trace-rule-selection") == 0) { options.trace.rule_selection = enable_p; } else if (strcmp (argp, "trace-insn-insertion") == 0) { options.trace.insn_insertion = enable_p; } else if (strcmp (argp, "trace-insn-expansion") == 0) { options.trace.insn_expansion = enable_p; } else if (strcmp (argp, "jumps") == 0) { options.gen.code = generate_jumps; } else if (strcmp (argp, "field-widths") == 0) { options.insn_specifying_widths = enable_p; } else if (strcmp (argp, "omit-line-numbers") == 0) { file_references = lf_omit_references; } else { error (NULL, "Unknown option %s\n", optarg); } break; } case 'i': isa = load_insn_table (optarg, cache_rules); if (isa->illegal_insn == NULL) error (NULL, "illegal-instruction missing from insn table\n"); break; case 'x': gen = do_gen (isa, decode_rules); break; case 'o': decode_rules = load_decode_table (optarg); break; case 'k': if (isa != NULL) error (NULL, "Cache file must appear before the insn file\n"); cache_rules = load_cache_table (optarg); break; case 'n': real_file_name = strdup(optarg); break; case 'h': is_header = 1; break; case 'c': case 'd': case 'e': case 'f': case 'm': case 'r': case 's': case 't': { lf *file = lf_open(optarg, real_file_name, file_references, (is_header ? lf_is_h : lf_is_c), argv[0]); if (gen == NULL && ch != 't' && ch != 'm' && ch != 'f') { options.warning (NULL, "Explicitly generate tables with -x option\n"); gen = do_gen (isa, decode_rules); } lf_print__file_start(file); switch (ch) { case 'm': if (is_header) gen_model_h (file, isa); else gen_model_c (file, isa); break; case 't': if (is_header) gen_itable_h (file, isa); else gen_itable_c (file, isa); break; case 'f': if (is_header) gen_support_h (file, isa); else gen_support_c (file, isa); break; case 'r': if (is_header) options.warning (NULL, "-hr option ignored\n"); else gen_run_c (file, gen); break; case 's': if(is_header) gen_semantics_h (file, gen->semantics, isa->max_nr_words); else gen_semantics_c (file, gen->semantics, isa->caches); break; case 'd': if (is_header) gen_idecode_h (file, gen, isa, cache_rules); else gen_idecode_c (file, gen, isa, cache_rules); break; case 'e': if (is_header) gen_engine_h (file, gen, isa, cache_rules); else gen_engine_c (file, gen, isa, cache_rules); break; case 'c': if (is_header) gen_icache_h (file, gen->semantics, isa->functions, isa->max_nr_words); else gen_icache_c (file, gen->semantics, isa->functions, cache_rules); break; } lf_print__file_finish(file); lf_close(file); is_header = 0; } real_file_name = NULL; break; default: ERROR ("Bad switch"); } } return (0); }