Esempio n. 1
0
def _shift_and_fix_registers(registers, offset, addresses, min_address):
    """Shift register contents."""
    sregisters = []
    for register in registers:
        register = register.copy()
        if not register.name.startswith("GPR"):
            # Do not shift not GPR registers
            sregisters.append(register)
            continue

        # if GPR value is a negative one, do not shift it
        value = twocs_to_int(register.value, 64)
        if value < 0:
            sregisters.append(register)
            continue

        if not ((addresses[0] <= register.value < addresses[1]) and
                register.value > min_address):
            sregisters.append(register)
            continue

        distance = min((abs(register.value - addr) for addr in addresses[2]))
        if distance > _FIX_ADDRESS_TOLERANCE:
            sregisters.append(register)
            continue

        print_info(
            "Shift '%s' from '0x%016X' to '0x%016X'" %
            (register.name,
             register.value,
             register.value + offset),
        )
        register.value = register.value + offset

        fmt_str = "{0:064b}"
        value_coded = fmt_str.format(register.value)
        if len(value_coded) > 64:
            print_warning(
                "Overflow during shifting. Cropping of"
                " register '%s'" % register.name
            )
            register.value = int(value_coded[-64:], 2)
        sregisters.append(register)

    return sregisters
Esempio n. 2
0
def dump_mpt(input_file_fd, target, arguments):
    """

    :param input_file_fd:
    :type input_file_fd:
    :param target:
    :type target:
    :param arguments:
    :type arguments:
    """

    try:
        contents = input_file_fd.read()
        if six.PY3 and not isinstance(contents, str):
            contents = contents.decode()
    except KeyboardInterrupt:
        print_info("No input data provided. Exiting...")
        exit(1)

    print_info("Parsing input file...")

    print_info("Sections to parse: %s" % arguments['sections'])

    var_defs, req_defs, instr_defs = \
        interpret_objdump(contents, target,
                          strict=arguments.get('strict', False),
                          sections=arguments['sections'],
                          start_address=arguments['from_address'],
                          end_address=arguments['to_address'])

    print_info("Input file parsed")

    print_info(
        "%d instructions processed from the input file" % len(instr_defs)
    )

    if var_defs != []:
        print_info(
            "Variables referenced and detected in the dump: %s" %
            ','.join([var.name for var in var_defs])
        )

    if req_defs != []:
        print_warning(
            "Variables referenced and *NOT* detected in the dump: %s" %
            ','.join([var.name for var in req_defs])
        )
        print_warning(
            "You might need to edit the generated MPT to fix the"
            " declaration of such variables"
        )

    print_info("Generating the MPT contents...")

    mpt_config = mpt_configuration_factory()

    if 'default_code_address' in arguments:
        mpt_config.set_default_code_address(arguments['default_code_address'])
    else:
        mpt_config.set_default_code_address(instr_defs[0].address.displacement)

    if 'default_data_address' in arguments:
        mpt_config.set_default_data_address(arguments['default_data_address'])
    else:
        mpt_config.set_default_data_address(0)

    if arguments.get('elf_abi', False):

        kwargs = {}
        if "stack_name" in arguments:
            kwargs["stack_name"] = arguments["stack_name"]
        if "stack_address" in arguments:
            kwargs["stack_address"] = Address(
                base_address="code",
                displacement=arguments["stack_address"]
            )

        variables, instructions = target.elf_abi(
            arguments["stack_size"], arguments.get(
                "start_symbol", None
            ), **kwargs
        )

        for variable in variables:
            req_defs.append(variable_to_test_definition(variable))

        address = instr_defs[0].address
        for instr in reversed(instructions):
            instr_defs = [instruction_to_definition(instr)] + instr_defs
            address -= instr.architecture_type.format.length

        if address.displacement < 0:
            print_error(
                "Default code address is below zero after"
                " adding the initialization code."
            )
            print_error(
                "Check/modify the objdump provided or do not use"
                " the elf_abi flag."
            )
            exit(-1)

        mpt_config.set_default_code_address(address.displacement)

    instr = None
    if "end_branch_to_itself" in arguments:
        instr = target.branch_to_itself()
    elif arguments.get('elf_abi', False):
        instr = target.nop()

    if instr is not None:
        instr.set_label("ELF_ABI_EXIT")
        instr_defs.append(instruction_to_definition(instr))

    for var in var_defs + req_defs:
        mpt_config.register_variable_definition(var)

    mpt_config.register_instruction_definitions(instr_defs)

    print_info("Dumping MPT to '%s'" % arguments['output_mpt_file'])
    mpt_parser = mpt_parser_factory()
    mpt_parser.dump_mpt_config(mpt_config, arguments['output_mpt_file'])
Esempio n. 3
0
def _compute_reset_code(target, test_def, args):
    instructions = interpret_asm(
        test_def.code, target, [var.name for var in test_def.variables],
        show_progress=True,
    )

    # TODO: This can be done in parallel or look for speed up the process
    instructions = [
        instruction_from_definition(instr) for instr in instructions
    ]

    instruction_dict = {}
    address = test_def.default_code_address
    progress = Progress(
        len(test_def.roi_memory_access_trace),
        msg="Building instruction dictionary",
    )
    for instr in instructions:
        progress()
        if instr.address is not None:
            if instr.address.base_address == "code":
                address = test_def.default_code_address + \
                          instr.address.displacement
                instr.set_address(address)
        else:
            address = address + instr.architecture_type.format.length
            instr.set_address(address)
        instruction_dict[instr.address] = instr

    free_regs = []
    written_after_read_regs = []
    read_regs = []
    level = 0
    dynamic_count = 0
    progress = Progress(
        len(test_def.roi_memory_access_trace),
        msg="Evaluating register usage",
    )
    reset_regs = set()
    for access in test_def.roi_memory_access_trace:
        progress()

        if access.data_type == "D":
            continue

        dynamic_count += 1
        try:
            instr = instruction_dict[access.address]
            uses = instruction_dict[access.address].uses()
            sets = instruction_dict[access.address].sets()

        except KeyError:
            print_error(
                "Access to from instruction at address "
                "0x%016X registered but such instruction is not"
                " present in the definition." % access.address,
            )
            exit(1)

        # Calls
        if instr.mnemonic == "BL":
            level += 1
        elif instr.mnemonic == "BCL":
            level += 1
        elif instr.mnemonic == "BCCTRL":
            if instr.operands()[2].value in [0, 3]:
                level += 1

        # Returns
        if instr.mnemonic == "BCLR":
            if (((instr.operands()[0].value & 0b10100) == 20) and
                    (instr.operands()[2].value == 0)):
                level -= 1

        # TODO: this should include Z and RISCV instructions for call
        # and return, but currently we do not have memory access traces
        # for such platforms

        for reg in uses:
            if reg not in read_regs:
                read_regs.append(reg)

        for reg in sets:
            if reg in free_regs:
                continue
            elif reg not in read_regs:
                free_regs.append(reg)
            elif reg not in written_after_read_regs:
                written_after_read_regs.append(reg)

        reset_regs = set(read_regs).intersection(
            set(written_after_read_regs),
        )

    reset_regs = sorted(reset_regs)

    assert len(free_regs) == len(set(free_regs))
    assert len(set(free_regs).intersection(set(reset_regs))) == 0

    if len(test_def.roi_memory_access_trace) == 0:
        # We do not have memory access trace, assume calling conventions
        reset_regs = target.volatile_registers

    reset_regs = [
        reg for reg in reset_regs if reg in target.volatile_registers]

    if len(reset_regs) == 0 and len(test_def.roi_memory_access_trace) == 0:
        print_info(
            "No memory access trace found. Resetting volatile registers."
        )
        reset_regs = target.volatile_registers

    unused_regs = sorted(
        (reg for reg in target.registers.values() if reg not in read_regs),
    )

    #
    # Make sure scratch registers are reset last
    #
    for reg in target.scratch_registers:
        if reg in reset_regs:
            reset_regs.remove(reg)
            reset_regs.append(reg)

    free_regs = unused_regs + free_regs

    # Know which ones are not used (or written) and which ones are used
    # Use them as base / temporal registers for addresses

    # Check addresses
    conflict_addresses = {}
    new_ins = []
    progress = Progress(
        len(test_def.roi_memory_access_trace),
        msg="Evaluating memory usage",
    )
    for access in test_def.roi_memory_access_trace:
        progress()
        if access.data_type == "I":
            continue
        val = conflict_addresses.get(
            access.address,
            [access.length, access.access_type],
        )
        if access.access_type not in val[1]:
            val[1] += access.access_type
        val[0] = max(val[0], access.length)
        conflict_addresses[access.address] = val

    fix_addresses = []
    for address in conflict_addresses:
        value = conflict_addresses[address]
        if value[1] == "RW":
            wvalue = None
            for var in test_def.variables:
                if var.var_type.upper() in ["CHAR", "UINT8_T"]:
                    elem_size = 1
                else:
                    raise NotImplementedError
                end_address = var.address + var.num_elements * elem_size
                if var.address <= address <= end_address:
                    offset = int((address - var.address) / elem_size)
                    svalue = var.init_value[
                        offset:offset + int(value[0] / elem_size)
                    ]
                    svalue = "".join(["%02X" % tval for tval in svalue])
                    wvalue = int(svalue, 16)
                    break

            if wvalue is None:
                print_error(
                    "Unable to restore original value for address 0x%X" %
                    address,
                )
                exit(1)

            if value[0] <= 8:
                fix_addresses.append((address, value[0], wvalue))
            else:
                for selem in range(0, value[0]//8):
                    sfmt = "%%0%dX" % (2*value[0])
                    nvalue = sfmt % wvalue
                    nvalue = int(nvalue[selem*16:(selem+1)*16], 16)
                    fix_addresses.append(
                        (address + selem * 8,
                         8,
                         nvalue)
                    )

    reset_steps = []

    context = Context()
    context.set_symbolic(True)

    if len(fix_addresses) > 0:

        # TODO: This can be optimized. Reduce the number of instructions to
        # be added by sorting the reset code (shared values or similar
        # addresses)
        # TODO: This can be optimized for use vector registers when
        # needed
        #
        print_info("Adding instructions to reset memory state")
        reset_register = [
            reg
            for reg in free_regs
            if reg.type.used_for_address_arithmetic and
            reg.name != "GPR0"
        ][0]

        for address, length, value in fix_addresses:

            address_obj = Address(base_address="data", displacement=address)
            new_instructions = target.set_register(
                reset_register, value, context, opt=False,
            )

            for ins in new_instructions:
                ins.add_comment(
                    "Reset code. Setting %s to 0X%016X" %
                    (reset_register.name, value),
                )

            reset_steps.append([new_instructions[:], reset_register, value])
            context.set_register_value(reset_register, value)

            try:
                store_ins = target.store_integer(
                    reset_register, address_obj, length * 8, context,
                )
                new_instructions += store_ins
                reset_steps.append(
                    [store_ins, reset_register, address_obj, length],
                )

            except MicroprobeCodeGenerationError:
                areg = [
                    reg for reg in free_regs
                    if reg.type.used_for_address_arithmetic and reg.name !=
                    "GPR0"
                ][1]

                set_ins = target.set_register(
                    areg, address, context, opt=False,
                )
                new_instructions += set_ins
                reset_steps.append([set_ins, areg, address_obj])

                context.set_register_value(areg, address_obj)

                store_ins = target.store_integer(
                    reset_register, address_obj, length * 8, context,
                )
                new_instructions += store_ins
                reset_steps.append(
                    [store_ins, reset_register, address_obj, length],
                )

                for ins in set_ins:
                    ins.add_comment(
                        "Reset code. Setting %s to 0X%016X" %
                        (areg.name, address),
                    )

            for ins in store_ins:
                ins.add_comment(
                    "Reset code. Setting mem content in 0X%016X" % (address),
                    )

            new_ins.extend(new_instructions)

    # Reset contents of used registers
    for reset_register in reset_regs:
        try:
            value = [
                reg for reg in test_def.registers if reg.name ==
                reset_register.name
            ][0].value
        except IndexError:
            continue

        new_instructions = target.set_register(
            reset_register, value, context, opt=False,
        )
        reset_steps.append([new_instructions, reset_register, value])
        context.set_register_value(reset_register, value)

        for ins in new_instructions:
            ins.add_comment(
                "Reset code. Setting %s to 0X%016X" %
                (reset_register.name, value),
            )

        new_ins.extend(new_instructions)

    try:
        overhead = (((len(new_ins) * 1.0) / dynamic_count) * 100)
    except ZeroDivisionError:
        print_warning("Unable to compute overhead. Zero dynamic instruction "
                      "count")
        overhead = 0

    print_info(
        "%03.2f%% overhead added by resetting code" % overhead,
    )
    if overhead > args['wrap_endless_threshold']:
        print_error(
            "Instructions added: %d" % len(new_ins),
        )
        print_error(
            "Total instructions: %d" % dynamic_count,
        )
        print_error(
            "Reset code above --wrap-endless-threshold. Stopping generation.",
        )
        exit(1)

    return new_ins, overhead, reset_steps
Esempio n. 4
0
def dump_mpt(input_file, target, init_data, arguments):
    """

    :param input_file:
    :type input_file:
    :param target:
    :type target:
    :param init_data:
    :type init_data:
    :param arguments:
    :type arguments:
    """

    input_file_fd = io.open(input_file, 'r')
    contents = input_file_fd.read()

    if six.PY2:
        contents = contents.encode("ascii")
    elif six.PY3:
        pass

    print_info("Parsing input file...")

    var_defs, req_defs, instr_defs = \
        interpret_objdump(contents, target,
                          strict=arguments.get('strict', False),
                          sections=["microprobe.text"])

    print_info("Input file parsed")

    print_info("%d instructions processed from the input file" %
               len(instr_defs))

    if var_defs != []:
        print_info("Variables referenced and detected in the dump: %s" %
                   ','.join([var.name for var in var_defs]))

    if req_defs != []:
        print_warning(
            "Variables referenced and *NOT* detected in the dump: %s" %
            ','.join([var.name for var in req_defs]))
        print_warning("You might need to edit the generated MPT to fix the"
                      " declaration of such variables")

    print_info("Generating the MPT contents...")

    mpt_config = mpt_configuration_factory()

    mpt_config.set_default_code_address(arguments['default_code_address'])
    mpt_config.set_default_data_address(arguments['default_data_address'])

    kwargs = {}
    if "stack_name" in arguments:
        kwargs["stack_name"] = arguments["stack_name"]
    if "stack_address" in arguments:
        kwargs["stack_address"] = Address(
            base_address="code", displacement=arguments["stack_address"])

    variables, instructions = target.elf_abi(arguments["stack_size"],
                                             "c2mpt_function", **kwargs)

    for variable in variables:
        req_defs.append(variable_to_test_definition(variable))

    address = instr_defs[0].address
    for instr in reversed(instructions):
        instr_defs = [instruction_to_definition(instr)] + instr_defs
        address -= instr.architecture_type.format.length

    if address.displacement < 0:
        print_error("Default code address is below zero after"
                    " adding the initialization code.")
        print_error("Check/modify the objdump provided or do not use"
                    " the elf_abi flag.")
        _exit(-1)

    if "end_branch_to_itself" in arguments:
        instr = target.branch_to_itself()
    else:
        instr = target.nop()

    instr.set_label("ELF_ABI_EXIT")
    instr_defs.append(instruction_to_definition(instr))

    mpt_config.set_default_code_address(address.displacement)

    initialized_variables = {}

    mindisplacement = None
    for data in init_data.split('\n'):

        if data.strip() == "":
            continue

        if data.startswith("WARNING"):
            print_warning(data.split(":")[1].strip())
            continue

        name = data.split("=")[0].strip()
        values = ast.literal_eval(data.split("=")[1].strip())
        initialized_variables[name] = values

        if mindisplacement is None:
            mindisplacement = values[2]
            # TODO: this is unsafe. We should compute the real size
            maxdisplacement = values[2] + (values[1] * 8)
        else:
            mindisplacement = min(values[2], mindisplacement)
            maxdisplacement = max(values[2] + (values[1] * 8), maxdisplacement)

    if "host_displacement" in arguments:
        mindisplacement = arguments.get("host_displacement", mindisplacement)

    for name, values in initialized_variables.items():
        values[2] = values[2] - mindisplacement + \
            arguments['default_data_address']

    if 'fix_displacement' in arguments:
        for name, values in initialized_variables.items():
            if "*" in values[0] and isinstance(values[4], list):
                new_values = []
                for value in values[4]:
                    if value <= maxdisplacement and value >= mindisplacement:
                        value = value - mindisplacement + \
                            arguments['default_data_address']
                    new_values.append(value)
                values[4] = new_values
            elif "*" in values[0] and isinstance(values[4], int):
                if (values[4] <= maxdisplacement
                        and values[4] >= mindisplacement):
                    values[4] = values[4] - mindisplacement + \
                        arguments['default_data_address']
            elif values[0] == "uint8_t" and isinstance(values[4], list):
                if len(values[4]) > 8:
                    new_values = "".join(["%02x" % elem for elem in values[4]])

                    # Enable this for testing switched endianness
                    # new_values = [new_values[idx:idx + 2]
                    #              for idx in range(0, len(new_values), 2)]
                    # new_values = new_values[::-1]
                    # new_values = "".join(new_values)

                    new_values = _fix_displacement(new_values, mindisplacement,
                                                   maxdisplacement, arguments)

                    values[4] = [
                        int(new_values[idx:idx + 2], 16)
                        for idx in range(0, len(new_values), 2)
                    ]

    for name, values in initialized_variables.items():

        mpt_config.register_variable_definition(
            MicroprobeTestVariableDefinition(name, *values))
        print_info("Init values for variable '%s' parsed" % name)

    for var in var_defs + req_defs:
        if var.name in list(initialized_variables.keys()):
            continue
        if var.name != arguments["stack_name"]:
            print_warning("Variable '%s' not registered in the C file "
                          "using the macros provided!" % var.name)
        mpt_config.register_variable_definition(var)

    mpt_config.register_instruction_definitions(instr_defs)

    print_info("Dumping MPT to '%s'" % arguments['output_mpt_file'])
    mpt_parser = mpt_parser_factory()
    mpt_parser.dump_mpt_config(mpt_config, arguments['output_mpt_file'])
Esempio n. 5
0
def dump_objdump(target, arguments):
    """

    :param target:
    :type target:
    :param arguments:
    :type arguments:
    """

    cmd = "'%s' -Ax -tx1 -v '%s'" % (arguments['od_bin'],
                                     arguments['input_bin_file'])
    text_string = run_cmd_output(cmd)
    bintext = []
    for line in text_string.split('\n'):
        if line == "":
            continue
        bintext.append("".join(line.split(' ')[1:]))

    instrs = interpret_bin("".join(bintext), target)

    print("")
    print("%s:\tfile format raw %s" %
          (os.path.basename(arguments['input_bin_file']), target.isa.name))
    print("")
    print("")
    print("Disassembly of section .raw:")
    print("")

    maxlen = max(len(instr.asm[2:]) for instr in instrs)
    if maxlen % 2 != 0:
        maxlen = maxlen + 1
    maxlen += maxlen // 2

    counter = arguments['start_address']

    label_dict = RejectingOrderedDict()
    instr_dict = RejectingOrderedDict()

    for instr_def in instrs:
        instr = instruction_from_definition(instr_def, fix_relative=False)
        asm = instr.assembly().lower()

        relative = None
        absolute = None
        if instr.branch:

            for memoperand in instr.memory_operands():

                if not memoperand.descriptor.is_branch_target:
                    continue

                for operand in memoperand.operands:

                    if operand.type.address_relative:
                        relative = operand.value

                    if operand.type.address_absolute:
                        absolute = operand.value

        masm = instr_def.asm[2:]
        if len(masm) % 2 != 0:
            masm = "0" + masm

        binary = " ".join([str(masm)[i:i + 2] for i in range(0, len(masm), 2)])

        label = None
        if counter == 0:
            label = ".raw"
            label_dict[counter] = label
        elif counter in label_dict:
            label = label_dict[counter]

        rtarget = None
        atarget = None
        if relative is not None or absolute is not None:

            if relative is not None:
                assert absolute is None

                if isinstance(relative, six.integer_types):
                    target_addr = counter + relative
                    rtarget = relative
                elif isinstance(relative, Address):
                    target_addr = counter + relative.displacement
                    rtarget = relative.displacement
                else:
                    raise NotImplementedError

            if absolute is not None:
                assert relative is None

                if isinstance(absolute, six.integer_types):
                    target_addr = absolute
                    atarget = absolute
                elif isinstance(absolute, Address):
                    target_addr = absolute.displacement
                    atarget = absolute.displacement
                else:
                    raise NotImplementedError

            if target_addr not in label_dict:
                label_dict[target_addr] = "branch_%x" % target_addr

            if target_addr in instr_dict:
                instr_dict[target_addr][2] = label_dict[target_addr]

        instr_dict[counter] = [binary, asm, label, rtarget, atarget]
        counter = counter + len(masm) // 2

    str_format = "%8s:\t%-" + str(maxlen) + "s\t%s"
    addresses = []
    for counter, values in instr_dict.items():

        binary, asm, label, rtarget, atarget = values

        if label is not None:
            print("%016x <%s>:" % (counter, label))

        cformat = str_format
        if rtarget is not None:
            cformat = str_format + "\t <%s>" % (label_dict[counter + rtarget])
        elif atarget is not None:
            cformat = str_format + "\t <%s>" % (label_dict[atarget])

        print(cformat % (hex(counter)[2:], binary, asm))
        addresses.append(counter)

    error = False
    for key in label_dict.keys():
        if key not in addresses:
            print_warning("Target address '%s' not in the objdump" % hex(key))
            error = True

    if error and arguments['strict']:
        print_error("Check target addresses of relative branches")
        exit(-1)
Esempio n. 6
0
def generate(test_definition, outputfile, target, **kwargs):
    """
    Microbenchmark generation policy

    :param test_definition: Test definition object
    :type test_definition: :class:`MicroprobeTestDefinition`
    :param outputfile: Outputfile name
    :type outputfile: :class:`str`
    :param target: Target definition object
    :type target: :class:`Target`
    """

    variables = test_definition.variables

    if 'raw_bin' in kwargs:
        print_info("Interpreting RAW dump...")

        sequence = []
        raw_dict = {}
        current_address = 0

        for entry in test_definition.code:
            if (not entry.assembly.upper().startswith("0X")
                    and not entry.assembly.upper().startswith("0B")):
                raise MicroprobeMPTFormatError(
                    "This is not a RAW dump as it contains "
                    "assembly (%s)" % entry.assembly)

            if entry.label is not None:
                raise MicroprobeMPTFormatError(
                    "This is not a RAW dump as it contains "
                    "labels (%s)" % entry.label)

            if entry.decorators not in ['', ' ', None, []]:
                raise MicroprobeMPTFormatError(
                    "This is not a RAW dump as it contains "
                    "decorators (%s)" % entry.decorators)

            if entry.comments not in ['', ' ', None, []]:
                raise MicroprobeMPTFormatError(
                    "This is not a RAW dump as it contains "
                    "comments (%s)" % entry.comments)

            if entry.address is not None:
                current_address = entry.address

            if current_address not in raw_dict:
                raw_dict[current_address] = ""

            # Assume that raw dump use a 4 bytes hex dump
            if len(entry.assembly) != 10:
                raise MicroprobeMPTFormatError(
                    "This is not a RAW 4-byte dump as it contains "
                    "lines with other formats (%s)" % entry.assembly)

            raw_dict[current_address] += entry.assembly[2:]

        if len(raw_dict) > 1:
            address_ant = sorted(raw_dict.keys())[0]
            len_ant = len(raw_dict[address_ant]) // 2

            # Assume that raw dump use a 4 bytes hex dump
            assert len_ant % 4 == 0

            for address in sorted(raw_dict.keys())[1:]:
                if address_ant + len_ant == address:
                    raw_dict[address_ant] += raw_dict[address]
                    len_ant = len(raw_dict[address_ant]) // 2
                    raw_dict.pop(address)
                else:
                    len_ant = len(raw_dict[address]) // 2
                    address_ant = address

                # Assume that raw dump use a 4 bytes hex dump
                assert len_ant % 4 == 0

        sequence = []
        for address in sorted(raw_dict.keys()):

            # Endianess will be big endian, because we are concatenating
            # full words resulting in the higher bits being encoded first

            code = interpret_bin(raw_dict[address],
                                 target,
                                 safe=True,
                                 little_endian=False,
                                 word_length=4)
            code[0].address = address
            sequence.extend(code)

    else:
        print_info("Interpreting assembly...")
        sequence = interpret_asm(test_definition.code, target,
                                 [var.name for var in variables])

    if len(sequence) < 1:
        raise MicroprobeMPTFormatError(
            "No instructions found in the 'instructions' entry of the MPT"
            " file. Check the input file.")

    registers = test_definition.registers
    raw = test_definition.raw

    for instruction_def in sequence:
        if instruction_def.address is not None:
            print_warning("Instruction address not needed in '%s'" %
                          instruction_def.asm)

    if test_definition.default_data_address is not None:
        print_warning("Default data address not needed")

    if test_definition.default_code_address is not None:
        print_warning("Default code address not needed")

    wrapper_name = "CWrapper"
    if kwargs.get("endless", False):
        print_warning("Using endless C wrapper")
        wrapper_name = "CInfGen"

    print_info("Creating benchmark synthesizer...")

    try:
        cwrapper = microprobe.code.get_wrapper(wrapper_name)
    except MicroprobeValueError as exc:
        raise MicroprobeException(
            "Wrapper '%s' not available. Check if you have the wrappers "
            "of the target installed or set up an appropriate "
            "MICROPROBEWRAPPERS environment variable. Original error was: %s" %
            (wrapper_name, str(exc)))

    wrapper_kwargs = {}
    wrapper = cwrapper(**wrapper_kwargs)

    synth = microprobe.code.Synthesizer(target, wrapper, extra_raw=raw)

    if len(registers) >= 0:
        print_info("Add register initialization pass")
        synth.add_pass(
            microprobe.passes.initialization.InitializeRegistersPass(
                registers, skip_unknown=True, warn_unknown=True))

    synth.add_pass(
        microprobe.passes.structure.SimpleBuildingBlockPass(len(sequence)))
    synth.add_pass(microprobe.passes.variable.DeclareVariablesPass(variables))
    synth.add_pass(
        microprobe.passes.instruction.ReproduceSequencePass(sequence))

    if kwargs.get("fix_indirect_branches", False):
        print_info("Fix indirect branches: On")
        synth.add_pass(
            microprobe.passes.address.UpdateInstructionAddressesPass())
        synth.add_pass(microprobe.passes.branch.FixIndirectBranchPass())

    if kwargs.get("fix_branch_next", False):
        print_info("Force branch to next: On")
        synth.add_pass(
            microprobe.passes.address.UpdateInstructionAddressesPass())
        synth.add_pass(microprobe.passes.branch.BranchNextPass(force=True))

    if kwargs.get("fix_memory_registers", False):
        kwargs["fix_memory_references"] = True

    if kwargs.get("fix_memory_references", False):
        synth.add_pass(
            microprobe.passes.memory.FixMemoryReferencesPass(
                reset_registers=kwargs.get("fix_memory_registers", False)))

    if kwargs.get("fix_memory_registers", False):
        print_info("Fix memory registers: On")
        synth.add_pass(microprobe.passes.register.NoHazardsAllocationPass())

    print_info("Synthesizing...")
    bench = synth.synthesize()

    # Save the microbenchmark
    synth.save(outputfile, bench=bench)
    return
def generate_genetic(compname, ipc):
    """Generate a microbenchmark stressing compname at the given ipc."""
    comps = []
    bcomps = []
    any_comp = False

    if compname.find("FXU") >= 0:
        comps.append(TARGET.elements["FXU0_Core0_SCM_Processor"])

    if compname.find("VSU") >= 0:
        comps.append(TARGET.elements["VSU0_Core0_SCM_Processor"])

    if len(comps) == 2:
        any_comp = True
    elif compname.find("noLSU") >= 0:
        bcomps.append(TARGET.elements["LSU0_Core0_SCM_Processor"])
    elif compname.find("LSU") >= 0:
        comps.append(TARGET.elements["LSU_Core0_SCM_Processor"])

    if (len(comps) == 1 and ipc > 2) or (len(comps) == 2 and ipc > 4):
        return True

    for elem in os.listdir(DIRECTORY):
        if not elem.endswith(".c"):
            continue
        if elem.startswith("%s:IPC:%.2f:DIST" % (compname, ipc)):
            print_info("Already generated: %s %d" % (compname, ipc))
            return True

    print_info("Going for IPC: %f and Element: %s" % (ipc, compname))

    def generate(name, *args):
        """Benchmark generation function.

        First argument is name, second the dependency distance and the
        third is the average instruction latency.
        """
        dist, latency = args

        wrapper = microprobe.code.get_wrapper("CInfPpc")
        synth = microprobe.code.Synthesizer(TARGET, wrapper())
        synth.add_pass(
            microprobe.passes.initialization.InitializeRegistersPass(
                value=RNDINT))
        synth.add_pass(
            microprobe.passes.structure.SimpleBuildingBlockPass(BENCHMARK_SIZE)
        )
        synth.add_pass(
            microprobe.passes.instruction.SetInstructionTypeByElementPass(
                TARGET,
                comps,
                {},
                block=bcomps,
                avelatency=latency,
                any_comp=any_comp))
        synth.add_pass(
            microprobe.passes.register.DefaultRegisterAllocationPass(
                dd=dist))
        bench = synth.synthesize()
        synth.save(name, bench=bench)

    # Set the genetic algorithm parameters
    ga_params = []
    ga_params.append((0, 20, 0.05))  # Average dependency distance design space
    ga_params.append((2, 8, 0.05))  # Average instruction latency design space

    # Set up the search driver
    driver = microprobe.driver.genetic.ExecCmdDriver(
        generate, 20, 30, 30, "'%s' %f " %
        (COMMAND, ipc), ga_params)

    starttime = runtime.time()
    print_info("Start search...")
    driver.run(1)
    print_info("Search end")
    endtime = runtime.time()

    print_info("Genetic time::%s" % (
        datetime.timedelta(seconds=endtime - starttime))
    )

    # Check if we found a solution
    ga_params = driver.solution()
    score = driver.score()

    print_info("IPC found: %f, score: %f" % (ipc, score))

    if score < 20:
        print_warning("Unable to find an optimal solution with IPC: %f:" % ipc)
        print_info("Generating the closest solution...")
        generate(
            "%s/%s:IPC:%.2f:DIST:%.2f:LAT:%.2f-check" %
            (DIRECTORY, compname, ipc, ga_params[0], ga_params[1]),
            ga_params[0], ga_params[1]
        )
        print_info("Closest solution generated")
    else:
        print_info(
            "Solution found for %s and IPC %f -> dist: %f , "
            "latency: %f " %
            (compname, ipc, ga_params[0], ga_params[1]))
        print_info("Generating solution...")
        generate("%s/%s:IPC:%.2f:DIST:%.2f:LAT:%.2f" %
                 (DIRECTORY, compname, ipc, ga_params[0], ga_params[1]),
                 ga_params[0], ga_params[1]
                 )
        print_info("Solution generated")
    return True
Esempio n. 8
0
def generate(test_definition, outputfile, target, **kwargs):
    """
    Microbenchmark generation policy

    :param test_definition: Test definition object
    :type test_definition: :class:`MicroprobeTestDefinition`
    :param outputfile: Outputfile name
    :type outputfile: :class:`str`
    :param target: Target definition object
    :type target: :class:`Target`
    """

    variables = test_definition.variables
    print_info("Interpreting assembly...")
    sequence = interpret_asm(test_definition.code, target,
                             [var.name for var in variables])

    if len(sequence) < 1:
        raise MicroprobeMPTFormatError(
            "No instructions found in the 'instructions' entry of the MPT"
            " file. Check the input file.")

    registers = test_definition.registers
    raw = test_definition.raw

    for instruction_def in sequence:
        if instruction_def.address is not None:
            print_warning("Instruction address not needed in '%s'" %
                          instruction_def.asm)

    if test_definition.default_data_address is not None:
        print_warning("Default data address not needed")

    if test_definition.default_code_address is not None:
        print_warning("Default code address not needed")

    wrapper_name = "CWrapper"
    if kwargs.get("endless", False):
        print_warning("Using endless C wrapper")
        wrapper_name = "CInfGen"

    print_info("Creating benchmark synthesizer...")

    try:
        cwrapper = microprobe.code.get_wrapper(wrapper_name)
    except MicroprobeValueError as exc:
        raise MicroprobeException(
            "Wrapper '%s' not available. Check if you have the wrappers "
            "of the target installed or set up an appropriate "
            "MICROPROBEWRAPPERS environment variable. Original error was: %s" %
            (wrapper_name, str(exc)))

    wrapper_kwargs = {}
    wrapper = cwrapper(**wrapper_kwargs)

    synth = microprobe.code.Synthesizer(target, wrapper, extra_raw=raw)

    if len(registers) >= 0:
        print_info("Add register initialization pass")
        synth.add_pass(
            microprobe.passes.initialization.InitializeRegistersPass(
                registers, skip_unknown=True, warn_unknown=True))

    synth.add_pass(
        microprobe.passes.structure.SimpleBuildingBlockPass(len(sequence)))
    synth.add_pass(microprobe.passes.variable.DeclareVariablesPass(variables))
    synth.add_pass(
        microprobe.passes.instruction.ReproduceSequencePass(sequence))

    if kwargs.get("fix_memory_registers", False):
        kwargs["fix_memory_references"] = True

    if kwargs.get("fix_memory_references", False):
        synth.add_pass(
            microprobe.passes.memory.FixMemoryReferencesPass(
                reset_registers=kwargs.get("fix_memory_registers", False)))

    if kwargs.get("fix_memory_registers", False):
        print_info("Fix memory registers: On")
        synth.add_pass(microprobe.passes.register.NoHazardsAllocationPass())

    if kwargs.get("fix_branch_next", False):
        print_info("Force branch to next: On")
        synth.add_pass(
            microprobe.passes.address.UpdateInstructionAddressesPass())
        synth.add_pass(microprobe.passes.branch.BranchNextPass(force=True))

    if kwargs.get("fix_indirect_branches", False):
        print_info("Fix indirect branches: On")
        synth.add_pass(
            microprobe.passes.address.UpdateInstructionAddressesPass())
        synth.add_pass(microprobe.passes.branch.FixIndirectBranchPass())

    print_info("Synthesizing...")
    bench = synth.synthesize()

    # Save the microbenchmark
    synth.save(outputfile, bench=bench)
    return
Esempio n. 9
0
    def __call__(self, building_block, target):
        """

        :param building_block:
        :param target:

        """

        if not self._skip_unknown:
            for register_name in self._reg_dict:
                if register_name not in list(target.registers.keys()):
                    raise MicroprobeCodeGenerationError(
                        "Unknown register name: '%s'. Unable to set it" %
                        register_name)

        if self._warn_unknown:
            for register_name in self._reg_dict:
                if register_name not in list(target.registers.keys()):
                    print_warning(
                        "Unknown register name: '%s'. Unable to set it" %
                        register_name)

        for reg in target.registers.values():

            value = None
            elemsize = None

            if reg.name in self._reg_dict:
                value = self._reg_dict[reg.name]
                self._reg_dict.pop(reg.name)

            if (reg in building_block.context.reserved_registers
                    and not self._force_reserved):
                LOG.debug("Skip reserved - %s", reg)
                continue
            elif reg in target.control_registers:
                LOG.debug("Skip control - %s", reg)
                continue

            if value is None:
                if reg.used_for_vector_arithmetic:
                    if self._vect_value is not None:
                        value = self._vect_value
                        elemsize = self._vect_elemsize
                    else:
                        LOG.debug("Skip no vector default value provided - %s",
                                  reg)
                        continue
                elif reg.used_for_float_arithmetic:
                    if self._fp_value is not None:
                        value = self._fp_value
                    else:
                        LOG.debug("Skip no float default value provided - %s",
                                  reg)
                        continue
                else:
                    if self._value is not None:
                        value = self._value
                    else:
                        LOG.debug("Skip no default value provided - %s", reg)
                        continue

                while callable(value):
                    value = value()

                if reg.used_for_float_arithmetic:

                    value = ieee_float_to_int64(float(value))

                elif reg.used_for_vector_arithmetic:

                    if isinstance(value, float):
                        if elemsize != 64:
                            raise MicroprobeCodeGenerationError(
                                "Unable to initialize '%s' to '%s'. Only 64bit"
                                " vector element initialization is supported" %
                                (reg.name, (value, elemsize)))
                        value = ieee_float_to_int64(float(value))
                        value = "%d_%d" % (value, elemsize)
                    else:
                        value = "%d_%d" % (value, elemsize)

            LOG.debug("Set '%s' to '0x%x'", reg, value)

            if (target.wrapper.direct_initialization_support
                    and not self._force_code):

                try:
                    target.wrapper.register_direct_init(reg, value)
                except MicroprobeCodeGenerationError:
                    building_block.add_init(
                        target.set_register(reg, value,
                                            building_block.context))
                except MicroprobeDuplicatedValueError:
                    LOG.debug("Skip already set - %s", reg)
            else:
                building_block.add_init(
                    target.set_register(reg, value, building_block.context))

            building_block.context.set_register_value(reg, value)
Esempio n. 10
0
def dump_objdump(target, arguments):
    """

    :param target:
    :type target:
    :param arguments:
    :type arguments:
    """

    ifile = open(arguments['input_dma_file'], 'r')
    dataw = arguments['width_bytes']
    inputlines = ifile.readlines()
    ifile.close()

    progress = Progress(len(inputlines), msg="Lines parsed:")
    lines_dict = {}
    for idx, line in enumerate(inputlines):
        splitline = line.upper().split(" ")

        if len(splitline) != 3:
            raise MicroprobeDMAFormatError("Unable to parse line %d: %s" %
                                           (idx, line))

        if (splitline[0] != "D" or len(splitline[1]) != 16
                or len(splitline[1]) != 16):
            raise MicroprobeDMAFormatError("Unable to parse line %d: %s" %
                                           (idx, line))

        key = int(splitline[1], base=16)
        if key in lines_dict:
            print_warning("Address (%s) in line %d overwrites previous entry" %
                          (splitline[1], idx))

        lines_dict[key] = splitline[2][:-1]
        progress()

    current_key = None
    progress = Progress(len(list(lines_dict.keys())),
                        msg="Detecting segments:")
    for key in sorted(lines_dict):

        progress()

        if current_key is None:
            current_key = key
            continue

        current_address = current_key + (len(lines_dict[current_key]) // 2)

        if current_address == key:
            lines_dict[current_key] += lines_dict[key]
            lines_dict.pop(key)
        else:
            current_key = key

    instrs = []
    progress = Progress(len(list(lines_dict.keys())),
                        msg="Interpreting segments:")

    for key in sorted(lines_dict):
        progress()
        current_instrs = interpret_bin(lines_dict[key],
                                       target,
                                       safe=not arguments['strict'])
        current_instrs[0].address = Address(base_address='code',
                                            displacement=key)
        instrs += current_instrs

    maxlen = max([ins.format.length
                  for ins in target.instructions.values()] + [dataw]) * 2
    maxlen += maxlen // 2

    counter = 0
    label_dict = RejectingDict()
    instr_dict = RejectingDict()
    range_num = 1

    progress = Progress(len(instrs), msg="Computing labels:")
    for instr_def in instrs:
        progress()

        if instr_def.address is not None:
            counter = instr_def.address.displacement

        if instr_def.instruction_type is None:

            for idx in range(0, len(instr_def.asm), dataw * 2):

                label = None
                if instr_def.address is not None and idx == 0:
                    label = ".range_%x" % range_num
                    label_dict[counter] = label
                    range_num += 1
                elif counter in label_dict:
                    label = label_dict[counter]

                idx2 = min(idx + (dataw * 2), len(instr_def.asm))

                masm = instr_def.asm[idx:idx2].lower()
                binary = " ".join([
                    str(masm)[i:i + 2] for i in range(0, len(masm), 2)
                ]).lower()
                instr_dict[counter] = [binary, "0x" + masm, label, None, None]

                counter += (idx2 - idx) // 2

            continue

        instr = instruction_from_definition(instr_def, fix_relative=False)
        asm = instr.assembly().lower()

        relative = None
        absolute = None
        if instr.branch:

            for memoperand in instr.memory_operands():

                if not memoperand.descriptor.is_branch_target:
                    continue

                for operand in memoperand.operands:
                    if operand.type.address_relative:
                        relative = operand.value

                    if operand.type.address_absolute:
                        absolute = operand.value

        masm = instr_def.asm[2:]
        if len(masm) % 2 != 0:
            masm = "0" + masm

        binary = " ".join([str(masm)[i:i + 2] for i in range(0, len(masm), 2)])

        label = None
        if instr_def.address is not None:
            if counter not in label_dict:
                label = ".range_%x" % range_num
                label_dict[counter] = label
                range_num += 1
            else:
                label = label_dict[counter]
        elif counter in label_dict:
            label = label_dict[counter]

        rtarget = None
        atarget = None
        if relative is not None or absolute is not None:

            if relative is not None:
                assert absolute is None

                if isinstance(relative, int):
                    target_addr = counter + relative
                    rtarget = relative

                elif isinstance(relative, Address):
                    target_addr = counter + relative.displacement
                    rtarget = relative.displacement
                else:
                    raise NotImplementedError

            if absolute is not None:
                assert relative is None

                if isinstance(absolute, int):
                    target_addr = absolute
                    atarget = absolute
                elif isinstance(absolute, Address):
                    target_addr = absolute.displacement
                    atarget = absolute.displacement
                else:
                    raise NotImplementedError

            if target_addr not in label_dict:
                label_dict[target_addr] = "branch_%x" % target_addr

            if target_addr in instr_dict:
                instr_dict[target_addr][2] = label_dict[target_addr]

        instr_dict[counter] = [binary, asm, label, rtarget, atarget]
        counter = counter + (len(masm) // 2)

    print("")
    print("%s:\tfile format raw %s" %
          (os.path.basename(arguments['input_dma_file']), target.isa.name))
    print("")
    print("")
    print("Disassembly of section .code:")
    print("")

    str_format = "%8s:\t%-" + str(maxlen) + "s\t%s"
    for counter in sorted(instr_dict.keys()):

        binary, asm, label, rtarget, atarget = instr_dict[counter]

        if label is not None:
            print("%016x <%s>:" % (counter, label))

        cformat = str_format
        if rtarget is not None:
            cformat = str_format + "\t <%s>" % (label_dict[counter + rtarget])
        elif atarget is not None:
            cformat = str_format + "\t <%s>" % (label_dict[atarget])

        print(cformat % (hex(counter)[2:], binary, asm))
Esempio n. 11
0
def _process_preload_data(data, args, offset=0):
    data_size = args['preload_data'] / args['smt_mode']
    code_size = args['preload_code'] / args['smt_mode']
    only_loads = args.get('preload_data_only_loads', False)
    only_stores = args.get('preload_data_only_stores', False)

    if only_loads and only_stores:
        print_warning(
            "Both --preload-data-only-loads and --preload-data-only-stores"
            " specified. No data will be pre-load!",
        )

    if only_loads:
        data = [
            access for access in data if access.data_type == "I" or
            (
                access.data_type ==
                "D" and
                access.access_type == "R"
            )
        ]

    if only_stores:
        data = [
            access for access in data if access.data_type == "I" or
            (
                access.data_type ==
                "D" and
                access.access_type ==
                "R"
            )
        ]

    fdata = []
    if len(args['preload_data_range']) > 0:
        for access in data:
            if access.data_type == "I":
                fdata.append(access)
                continue

            for start, end in args['preload_data_range']:
                if access.address >= start and (
                        access.address + access.length - 1) < end:
                    fdata.append(access)
                    break
        data = fdata

    addresses_read = []
    ccode = 0
    cdata = 0
    for access in data:
        if access.data_type == "D" and cdata >= data_size:
            continue
        if access.data_type == "I" and ccode >= code_size:
            continue

        for address in range(access.address, access.address + access.length):
            if address in addresses_read:
                continue

            addresses_read.append(address)

            if access.data_type == "D":
                cdata += 1
            else:
                ccode += 1

    for idx in range(0, len(addresses_read)):
        addresses_read[idx] = addresses_read[idx] + offset

    return set(addresses_read)
Esempio n. 12
0
def _shift_and_fix_code(
    target, code, offset, addresses, reset_steps, registers,
        ):
    """Shift code and fix reset code."""
    scode = []
    for instruction in code:
        instruction = instruction.copy()
        # Fix and shift decorators (not need to modify code)
        for key, values in instruction.decorators.items():
            if not isinstance(values, list):
                values = [values]
            if key in ['MA', 'BT']:
                for idx in range(0, len(values)):
                    if addresses[0] <= values[idx] <= addresses[1]:
                        values[idx] = values[idx] + offset
        scode.append(instruction)

    cidx = 0
    context = Context()
    context.set_symbolic(False)

    for reset_step in reset_steps:

        rins = reset_step[0]
        cins = scode[cidx:cidx+len(rins)]
        rreg = reset_step[1]

        try:
            rval = [reg for reg in registers if reg.name == rreg.name][0].value
        except IndexError:
            # This was a support register to compute an address,
            # it should be fixed
            rval = 0

        for rin, cin in zip(rins, cins):
            if rin.name != cin.instruction_type.name:
                print_error("Unable to fix the reset code")
                exit(1)

        if len(reset_step) == 3:
            rins, reset_register, value = reset_step
            if not isinstance(value, six.integer_types):
                # All addresses should be offset
                value += offset
                nins = target.set_register(
                    reset_register,
                    value.displacement,
                    context,
                    opt=False,
                )
                print_info(
                    "Fixing reset code for reg: %s. "
                    "New value: 0x%016X" %
                    (rreg.name, value.displacement),
                )
            else:
                if abs(value-rval) == offset:
                    # This has been shifted, force offset
                    value += offset
                    print_info(
                        "Fixing reset code for reg: %s. "
                        "New value: 0x%016X" %
                        (rreg.name, value),
                    )
                nins = target.set_register(
                    reset_register, value, context, opt=False,
                )

            context.set_register_value(reset_register, value)
        elif len(reset_step) == 4:
            rins, reset_register, address_obj, length = reset_step
            # All addresses should be offsetted
            address_obj += offset
            nins = target.store_integer(
                reset_register, address_obj, length * 8, context,
            )
            print_info(
                "Fixing reset code for reg: %s. "
                "New value: 0x%016X" %
                (rreg.name, address_obj.displacement),
            )
        else:
            raise NotImplementedError(
                "Unable to shift and fix code"
            )

        if len(rins) != len(nins):
            print_error("Original resetting code:")
            for ins in rins:
                print_error(ins.assembly())
            print_error("New resetting code:")
            for ins in nins:
                print_error(ins.assembly())
            print_error("New resetting code differs from original in length")
            exit(1)

        for ins in nins:
            if len(reset_step) == 3:
                if not isinstance(value, six.integer_types):
                    value = value.displacement
                ins.add_comment(
                    "Reset code. Setting %s to 0X%016X" %
                    (reset_register.name, value),
                )
            else:
                ins.add_comment(
                    "Reset code. Setting mem content in 0X%016X" %
                    (address_obj.displacement),
                )

        for idx, (nin, cin) in enumerate(zip(nins, cins)):
            if nin.name != cin.instruction_type.name:
                print_warning("New code differs from original in opcodes")
            scode[cidx+idx] = instruction_to_definition(nin)
            scode[cidx+idx].comments = scode[cidx+idx].comments[1:]

        cidx += len(rins)

    return scode
Esempio n. 13
0
def _compute_offset(smt_shift, target, test_def):
    """Compute required offset bettween threads to avoid conflicts."""
    addresses = []

    instructions = interpret_asm(
        test_def.code, target, [var.name for var in test_def.variables],
    )
    instructions = [
        instruction_from_definition(instr) for instr in instructions
    ]

    address = test_def.default_code_address
    for instr in instructions:
        if instr.address is not None:
            if instr.address.base_address == "code":
                address = test_def.default_code_address + \
                          instr.address.displacement
                instr.set_address(address)
        else:
            address = address + instr.architecture_type.format.length

        addresses.append(address)

    for var in test_def.variables:
        addresses.append(var.address)
        if var.var_type.upper() in ["CHAR", "UINT8_T"]:
            addresses.extend(
                range(var.address, var.address + var.num_elements),
            )
        else:
            raise NotImplementedError(
                "Unable to compute touched addresses for "
                "type '%s'" % var.var_type
            )

    if test_def.roi_memory_access_trace:
        addresses = []
        for access in test_def.roi_memory_access_trace:
            addresses.extend(
                range(access.address, access.address + access.length),
            )

    offset = ((max(addresses) / (4 * 1024)) + 1) * (4 * 1024)
    offset = int(offset)
    max_range = offset
    min_range = (min(addresses) / (4 * 1024)) * (4 * 1024)

    print_info("Computed offset needed: %d bytes" % offset)
    print_info(
        "Computed offset needed: %d megabytes" %
        (offset / (1024 * 1024)),
    )

    if smt_shift != -1:
        if offset > smt_shift:
            print_warning(
                "Offset forced to be %d bytes. There is overlapping accross "
                "threads" % smt_shift,
            )
        else:
            print_info(
                "Offset forced to be %d bytes." % smt_shift,
            )
        return smt_shift, (min_range, max_range, set(addresses))

    return offset, (min_range, max_range, set(addresses))