diff --git a/m2isar/backends/etiss/architecture_writer.py b/m2isar/backends/etiss/architecture_writer.py index b28ddb6..a09a249 100644 --- a/m2isar/backends/etiss/architecture_writer.py +++ b/m2isar/backends/etiss/architecture_writer.py @@ -201,7 +201,7 @@ def write_arch_specific_cpp(core: arch.CoreDef, start_time: str, output_path: pa error_instr._size = bitsize # pylint: disable=protected-access error_fields = generate_fields(32, error_instr) - error_callbacks[bitsize] = generate_instruction_callback(core, error_instr, error_fields, True, BlockEndType.NONE) + error_callbacks[bitsize] = generate_instruction_callback(core, error_instr, error_fields, True, BlockEndType.NONE, False) logger.info("writing architecture specific file") diff --git a/m2isar/backends/etiss/instruction_generator.py b/m2isar/backends/etiss/instruction_generator.py index 7e203c6..49acb45 100644 --- a/m2isar/backends/etiss/instruction_generator.py +++ b/m2isar/backends/etiss/instruction_generator.py @@ -22,7 +22,7 @@ def generate_arg_str(arg: arch.FnParam): arg_name = f" {arg.name}" if arg.name is not None else "" return f'{instruction_utils.data_type_map[arg.data_type]}{arg.actual_size}{arg_name}' -def generate_functions(core: arch.CoreDef, static_scalars: bool, decls_only: bool): +def generate_functions(core: arch.CoreDef, static_scalars: bool, decls_only: bool, generate_coverage: bool): """Return a generator object to generate function behavior code. Uses function definitions in the core object. """ @@ -47,7 +47,7 @@ def generate_functions(core: arch.CoreDef, static_scalars: bool, decls_only: boo # set up a transformer context and generate code context = instruction_utils.TransformerContext(core.constants, core.memories, core.memory_aliases, fn_def.args, fn_def.attributes, - core.functions, 0, core_default_width, core_name, static_scalars, core.intrinsics, True) + core.functions, 0, core_default_width, core_name, static_scalars, core.intrinsics, generate_coverage, True) logger.debug("generating code for %s", fn_name) @@ -139,7 +139,7 @@ def generate_fields(core_default_width, instr_def: arch.Instruction): return (fields_code, asm_printer_code, seen_fields, enc_idx) -def generate_instruction_callback(core: arch.CoreDef, instr_def: arch.Instruction, fields, static_scalars: bool, block_end_on: BlockEndType): +def generate_instruction_callback(core: arch.CoreDef, instr_def: arch.Instruction, fields, static_scalars: bool, block_end_on: BlockEndType, generate_coverage: bool): patch_model(instruction_transform) instr_name = instr_def.name @@ -151,7 +151,7 @@ def generate_instruction_callback(core: arch.CoreDef, instr_def: arch.Instructio callback_template = Template(filename=str(template_dir/'etiss_instruction_callback.mako')) context = instruction_utils.TransformerContext(core.constants, core.memories, core.memory_aliases, instr_def.fields, instr_def.attributes, - core.functions, enc_idx, core_default_width, core_name, static_scalars, core.intrinsics) + core.functions, enc_idx, core_default_width, core_name, static_scalars, core.intrinsics, generate_coverage) # force a block end if necessary if ((arch.InstrAttribute.NO_CONT in instr_def.attributes @@ -186,7 +186,7 @@ def generate_instruction_callback(core: arch.CoreDef, instr_def: arch.Instructio return callback_str -def generate_instructions(core: arch.CoreDef, static_scalars: bool, block_end_on: BlockEndType): +def generate_instructions(core: arch.CoreDef, static_scalars: bool, block_end_on: BlockEndType, generate_coverage: bool): """Return a generator object to generate instruction behavior code. Uses instruction definitions in the core object. """ @@ -230,7 +230,7 @@ def generate_instructions(core: arch.CoreDef, static_scalars: bool, block_end_on instr_def.operation = new_op instr_def.throws = True - callback_str = generate_instruction_callback(core, instr_def, fields, static_scalars, block_end_on) + callback_str = generate_instruction_callback(core, instr_def, fields, static_scalars, block_end_on, generate_coverage) # render code for whole instruction templ_str = instr_template.render( diff --git a/m2isar/backends/etiss/instruction_transform.py b/m2isar/backends/etiss/instruction_transform.py index a86fc20..4ed1150 100644 --- a/m2isar/backends/etiss/instruction_transform.py +++ b/m2isar/backends/etiss/instruction_transform.py @@ -40,7 +40,7 @@ def operation(self: behav.Operation, context: TransformerContext): else: args.append(c) - if self.line_info is not None: + if self.line_info is not None and context.generate_coverage: CodeInfoTracker.insert(context.arch_name, self.line_info) code_lines.append(context.wrap_codestring(f"etiss_coverage_count(1, {self.line_info.id});")) @@ -59,15 +59,16 @@ def operation(self: behav.Operation, context: TransformerContext): before_line_infos = [] after_line_infos = [] - for l in flatten(arg.line_infos): - if l is not None: - CodeInfoTracker.insert(context.arch_name, l) + if context.generate_coverage: + for l in flatten(arg.line_infos): + if l is not None: + CodeInfoTracker.insert(context.arch_name, l) - if l.placement == LineInfoPlacement.BEFORE: - before_line_infos.append(str(l.id)) + if l.placement == LineInfoPlacement.BEFORE: + before_line_infos.append(str(l.id)) - elif l.placement == LineInfoPlacement.AFTER: - after_line_infos.append(str(l.id)) + elif l.placement == LineInfoPlacement.AFTER: + after_line_infos.append(str(l.id)) if len(before_line_infos) > 0: code_lines.append(context.wrap_codestring(f"etiss_coverage_count({len(before_line_infos)}, {', '.join(before_line_infos)});")) diff --git a/m2isar/backends/etiss/instruction_utils.py b/m2isar/backends/etiss/instruction_utils.py index 1be1f27..d8424f3 100644 --- a/m2isar/backends/etiss/instruction_utils.py +++ b/m2isar/backends/etiss/instruction_utils.py @@ -141,7 +141,7 @@ class TransformerContext: def __init__(self, constants: "dict[str, arch.Constant]", memories: "dict[str, arch.Memory]", memory_aliases: "dict[str, arch.Memory]", fields: "dict[str, arch.BitFieldDescr]", attributes: "list[arch.InstrAttribute]", functions: "dict[str, arch.Function]", - instr_size: int, native_size: int, arch_name: str, static_scalars: bool, intrinsics, ignore_static=False): + instr_size: int, native_size: int, arch_name: str, static_scalars: bool, intrinsics, generate_coverage: bool, ignore_static=False): self.constants = constants self.memories = memories @@ -154,6 +154,7 @@ def __init__(self, constants: "dict[str, arch.Constant]", memories: "dict[str, a self.arch_name = arch_name self.intrinsics = intrinsics self.static_scalars = static_scalars + self.generate_coverage = generate_coverage self.ignore_static = ignore_static diff --git a/m2isar/backends/etiss/instruction_writer.py b/m2isar/backends/etiss/instruction_writer.py index a155ead..9f25b3e 100644 --- a/m2isar/backends/etiss/instruction_writer.py +++ b/m2isar/backends/etiss/instruction_writer.py @@ -21,7 +21,7 @@ logger = logging.getLogger("instruction_writer") -def write_functions(core: arch.CoreDef, start_time: str, output_path: pathlib.Path, static_scalars: bool): +def write_functions(core: arch.CoreDef, start_time: str, output_path: pathlib.Path, static_scalars: bool, generate_coverage: bool): """Generate and write the {CoreName}Funcs.h file for ETISS.""" fn_set_header_template = Template(filename=str(template_dir/'etiss_function_set_header.mako')) @@ -42,7 +42,7 @@ def write_functions(core: arch.CoreDef, start_time: str, output_path: pathlib.Pa funcs_f.write(fn_set_str) # generate and write function declarations - for fn_name, templ_str in generate_functions(core, static_scalars, True): + for fn_name, templ_str in generate_functions(core, static_scalars, True, generate_coverage): logger.debug("writing function decl %s", fn_name) funcs_f.write(templ_str) @@ -59,12 +59,12 @@ def write_functions(core: arch.CoreDef, start_time: str, output_path: pathlib.Pa funcs_f.write(fn_impl_str) # generate and write function definitions - for fn_name, templ_str in generate_functions(core, static_scalars, False): + for fn_name, templ_str in generate_functions(core, static_scalars, False, generate_coverage): logger.debug("writing function def %s", fn_name) funcs_f.write(templ_str) def write_instructions(core: arch.CoreDef, start_time: str, output_path: pathlib.Path, separate: bool, static_scalars: bool, - block_end_on: BlockEndType): + block_end_on: BlockEndType, generate_coverage: bool): """Generate and write the instruction model C++ files for ETISS.""" instr_set_template = Template(filename=str(template_dir/'etiss_instruction_set.mako')) @@ -96,6 +96,6 @@ def write_instructions(core: arch.CoreDef, start_time: str, output_path: pathlib out_f.write(instr_set_str) # generate instruction behavior models - for instr_name, _, ext_name, templ_str in generate_instructions(core, static_scalars, block_end_on): + for instr_name, _, ext_name, templ_str in generate_instructions(core, static_scalars, block_end_on, generate_coverage): logger.debug("writing instruction %s", instr_name) outfiles.get(ext_name, outfiles['default']).write(templ_str) diff --git a/m2isar/backends/etiss/writer.py b/m2isar/backends/etiss/writer.py index bb4d463..e4af4b5 100755 --- a/m2isar/backends/etiss/writer.py +++ b/m2isar/backends/etiss/writer.py @@ -83,6 +83,7 @@ def setup(): parser.add_argument("--static-scalars", action=BooleanOptionalAction, default=True, help="Enable static detection for scalars.") parser.add_argument("--block-end-on", default="none", choices=[x.name.lower() for x in BlockEndType], help="Force end translation blocks on no instructions, uncoditional jumps or all jumps.") + parser.add_argument("--coverage", action=BooleanOptionalAction, default=False, help="Generate coverage tracking code into model.") parser.add_argument("--log", default="info", choices=["critical", "error", "warning", "info", "debug"]) args = parser.parse_args() @@ -168,8 +169,8 @@ def main(): write_arch_lib(core, start_time, output_path) write_arch_cmake(core, start_time, output_path, args.separate) write_arch_gdbcore(core, start_time, output_path) - write_functions(core, start_time, output_path, args.static_scalars) - write_instructions(core, start_time, output_path, args.separate, args.static_scalars, BlockEndType[args.block_end_on.upper()]) + write_functions(core, start_time, output_path, args.static_scalars, args.coverage) + write_instructions(core, start_time, output_path, args.separate, args.static_scalars, BlockEndType[args.block_end_on.upper()], args.coverage) with open(output_path / "coverage.csv", "w") as f: for c_id, c_info in sorted(CodeInfoTracker.tracker[core_name].items()):