void print_icache_internal_function_definition (lf *file, function_entry * function, void *data) { ASSERT (options.gen.icache); if (function->is_internal) { lf_printf (file, "\n"); lf_print__function_type_function (file, print_icache_function_type, "INLINE_ICACHE", "\n"); print_function_name (file, function->name, NULL, NULL, NULL, function_name_prefix_icache); lf_printf (file, "\n("); print_icache_function_formal (file, 0); lf_printf (file, ")\n"); lf_printf (file, "{\n"); lf_indent (file, +2); lf_printf (file, "/* semantic routine */\n"); if (options.gen.semantic_icache) { lf_print__line_ref (file, function->code->line); table_print_code (file, function->code); lf_printf (file, "error (\"Internal function must longjump\\n\");\n"); lf_printf (file, "return 0;\n"); } else { lf_printf (file, "return "); print_function_name (file, function->name, NULL, NULL, NULL, function_name_prefix_semantics); lf_printf (file, ";\n"); } lf_print__internal_ref (file); lf_indent (file, -2); lf_printf (file, "}\n"); } }
static void support_c_function (lf *file, function_entry * function, void *data) { ASSERT (function->type != NULL); print_support_function_name (file, function, 1 /*!is_definition */ ); lf_printf (file, "{\n"); lf_indent (file, +2); if (function->code == NULL) error (function->line, "Function without body (or null statement)"); lf_print__line_ref (file, function->code->line); table_print_code (file, function->code); if (function->is_internal) { lf_printf (file, "sim_engine_abort (SD, CPU, cia, \"Internal function must longjump\\n\");\n"); lf_printf (file, "return cia;\n"); } lf_indent (file, -2); lf_printf (file, "}\n"); lf_print__internal_ref (file); lf_printf (file, "\n"); }
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 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); }
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"); }