def find_isa_definitions(paths=None): if paths is None: paths = [] paths = paths + MICROPROBE_RC["architecture_paths"] \ + MICROPROBE_RC["default_paths"] results = [] isafiles = findfiles(paths, "^isa.yaml$") if len(isafiles) > 0: from microprobe.target import Definition for isafile in isafiles: try: isadef = read_yaml(isafile, SCHEMA) except MicroprobeYamlFormatError as exc: LOG.info("Exception: %s", exc) LOG.info("Skipping '%s'", isafile) continue try: definition = Definition(isafile, isadef["Name"], isadef["Description"]) if (definition not in results and not definition.name.endswith("common")): results.append(definition) except TypeError as exc: # Skip bad definitions LOG.info("Exception: %s", exc) LOG.info("Skipping '%s'", isafile) continue return results
def import_definition(cls, filenames, regtypes): """ :param filenames: :param regtypes: """ LOG.debug("Start") regs = {} for filename in filenames: reg_data = read_yaml(filename, SCHEMA) if reg_data is None: continue for elem in reg_data: name = elem["Name"] descr = elem.get("Description", "No description") rtype = elem["Type"] rrepr = elem["Representation"] rcodi = elem.get("Codification", elem["Representation"]) repeat = elem.get("Repeat", None) rfrom = 0 rto = 0 replace = "0" if rtype not in regtypes: raise MicroprobeArchitectureDefinitionError( "Unknown register type in definition of " "register '%s' in file '%s'" % (name, filename) ) if repeat: rfrom = repeat["From"] replace = "%s" % rfrom rto = repeat["To"] for index in range(rfrom, rto + 1): cname = name.replace(replace, "%d" % index) cdescr = descr.replace(replace, "%d" % index) crepr = rrepr.replace(replace, "%d" % index) ccodi = rcodi.replace(replace, "%d" % index) ctype = regtypes[rtype] regt = cls(cname, cdescr, ctype, crepr, ccodi) if cname in regs: raise MicroprobeArchitectureDefinitionError( "Duplicated register definition of '%s' found" " in '%s'" % (cname, filename) ) LOG.debug(regt) regs[cname] = regt LOG.debug("End") return regs
def import_definition(cls, filenames, dummy): """ :param cls: :type cls: :param filenames: :type filenames: :param dummy: :type dummy: """ LOG.info("Start importing element type definitions") element_types = {} for filename in filenames: element_type_data = read_yaml(filename, SCHEMA) if element_type_data is None: continue for elem in element_type_data: name = elem["Name"] descr = elem.get("Description", "No description") element_type = cls(name, descr) element_types[name] = element_type LOG.debug(element_type) for filename in filenames: import_properties(filename, element_types) LOG.info("End importing element type definitions") return element_types
def import_definition(cls, filenames, operands): """ :param filenames: :param operands: """ LOG.debug("Start") ifields = {} ifields_duplicated = {} for filename in filenames: ifield_data = read_yaml(filename, SCHEMA) if ifield_data is None: continue for elem in ifield_data: name = elem["Name"] descr = elem.get("Description", "No description") size = elem["Size"] show = elem.get("Show", False) fio = elem.get("IO", "?") operand_def = elem.get("Operand", "Zero") key = tuple([size, show, fio, operand_def]) if key in ifields_duplicated: LOG.warning( "Similar definition of instruction field: '%s' and" " '%s'. Check if definition needed.", name, ifields_duplicated[key]) else: ifields_duplicated[key] = name try: operand = operands[operand_def] except KeyError: raise MicroprobeArchitectureDefinitionError( "Unknown operand " "defined in instruction" " field '%s' in '%s'." % (name, filename)) ifield = cls(name, descr, size, show, fio, operand) if name in ifields: raise MicroprobeArchitectureDefinitionError( "Duplicated " "definition " "of instruction field" " '%s' found in '%s'" % (name, filename)) LOG.debug(ifield) ifields[name] = ifield LOG.debug("End") return ifields
def _read_uarch_extensions(uarchdefs, path): """ """ if "Extends" in uarchdefs[-1]: uarchdefval = uarchdefs[-1]["Extends"] del uarchdefs[-1]["Extends"] if not os.path.isabs(uarchdefval): uarchdefval = os.path.join(path, uarchdefval) uarchdef = read_yaml( os.path.join(uarchdefval, "microarchitecture.yaml"), SCHEMA) uarchdef["Path"] = uarchdefval uarchdefs.append(uarchdef) _read_uarch_extensions(uarchdefs, uarchdefval)
def import_definition(cls, filenames, dummy): """ :param filenames: :param dummy: """ LOG.debug("Start") regts = {} regts_duplicated = {} for filename in filenames: regt_data = read_yaml(filename, SCHEMA) for elem in regt_data: name = elem["Name"] size = elem["Size"] descr = elem.get("Description", "No description") u4aa = elem.get("AddressArithmetic", False) u4fa = elem.get("FloatArithmetic", False) u4va = elem.get("VectorArithmetic", False) regt = cls(name, descr, size, u4aa, u4fa, u4va) key = tuple([size, u4aa, u4fa, u4va]) if key in regts_duplicated: LOG.warning( "Similar definition of register types: '%s' and" " '%s'. Check if definition needed.", name, regts_duplicated[key]) else: regts_duplicated[key] = name LOG.debug(regt) if name in regts: raise MicroprobeArchitectureDefinitionError( "Duplicated " "definition of register type '%s' " "found in '%s'" % (name, filename)) regts[name] = regt LOG.debug("End") return regts
def _read_isa_extensions(isadefs, path): """ :param isadefs: :param path: """ if "Extends" in isadefs[-1]: isadefval = isadefs[-1]["Extends"] del isadefs[-1]["Extends"] if not os.path.isabs(isadefval): isadefval = os.path.join(path, isadefval) isadef = read_yaml(os.path.join(isadefval, "isa.yaml"), SCHEMA) isadef["Path"] = isadefval isadefs.append(isadef) _read_isa_extensions(isadefs, isadefval)
def import_properties(filename, objects): """ :param filename: :param objects: """ LOG.info("Start importing object properties") dirname = filename[::-1].replace('lmay.', 'sporp_', 1)[::-1] if not os.path.isdir(dirname): return for filename in os.listdir(dirname): if filename.startswith(".") or filename.endswith(".cache"): continue if not filename.endswith(".yaml"): continue property_definitions = read_yaml( os.path.join( dirname, filename ), SCHEMA ) for property_def in property_definitions: property_objs = RejectingDict() property_name = property_def["Name"] property_description = property_def.get( "Description", "No description" ) property_override = property_def.get("Override", False) property_default_value = property_def.get("Default", "__unset__") property_values = property_def.get("Values", {}) property_class = Property LOG.debug( "Importing property '%s - %s'", property_name, property_description ) if "Value" in property_def: # Single value property_value = property_def["Value"] default_property = property_class( property_name, property_description, property_value ) for obj in objects.values(): obj.register_property( default_property, force=property_override ) LOG.debug("Single value property") continue if ( property_default_value != "__unset__" and property_default_value != "NO_DEFAULT" ): default_property = property_class( property_name, property_description, property_default_value, default=True ) LOG.debug("Default value: %s", property_default_value) else: default_property = None LOG.debug("Default value: No default value set") for key, obj in objects.items(): if key not in property_values: if property_default_value == "NO_DEFAULT": continue if default_property is None: raise MicroprobeArchitectureDefinitionError( "Wrong property '%s' definition in file '%s'. " "Value for '%s' is not provided and a default " "value is not defined" % ( property_name, filename, key ) ) obj.register_property( default_property, force=property_override ) else: property_value = property_values[key] del property_values[key] property_value_key = property_value if isinstance(property_value, list): property_value_key = str(property_value) if property_value_key in property_objs: obj.register_property( property_objs[property_value_key], force=property_override ) else: new_property = property_class( property_name, property_description, property_value, default=False ) obj.register_property( new_property, force=property_override ) property_objs[property_value_key] = new_property for key, value in property_values.items(): LOG.warning( "'%s' not found. Property '%s' not set to '%s'", key, property_name, value ) LOG.info("Property '%s' imported", property_name) LOG.info("End importing object properties")
def import_definition(filenames, registers): """ :param filenames: :param registers: """ LOG.debug("Start") operands = {} operands_duplicated = {} register_types = tuple([reg.type.name for reg in registers.values()]) for filename in filenames: ope_data = read_yaml(filename, SCHEMA) if ope_data is None: continue for elem in ope_data: name = elem["Name"] descr = elem.get("Description", "No description") override = elem.get("Override", False) key = [] try: if "Registers" in elem: regnames = elem["Registers"] if isinstance(regnames, list): if len(regnames) == 1 and \ regnames[0] in register_types: regs = [ reg for reg in registers.values() if reg.type.name == regnames[0] ] else: regs = [ registers[regname] for regname in natural_sort(regnames) ] key.append(tuple(regnames)) else: regs = OrderedDict() for regname in natural_sort(regnames): regs[registers[regname]] = [] for regname2 in regnames[regname]: regs[registers[regname]].append( registers[regname2]) key.append( tuple([(k, tuple(v)) for k, v in regnames.items()])) address_base = elem.get("AddressBase", False) address_index = elem.get("AddressIndex", False) floating_point = elem.get("FloatingPoint", None) vector = elem.get("Vector", None) key.append(address_base) key.append(address_index) key.append(floating_point) key.append(vector) # Filter out Register without # representation (N/A) # # These are pseudo registers used in # simulation/emulation environment. # They are not architected registers. regs = [reg for reg in regs if reg.representation != 'N/A'] operand = OperandReg(name, descr, regs, address_base, address_index, floating_point, vector) elif "Min" in elem and "Max" in elem: minval = elem["Min"] maxval = elem["Max"] step = elem.get("Step", 1) novalues = elem.get("Except", []) address_index = elem.get("AddressIndex", False) shift = elem.get("Shift", 0) add = elem.get("Add", 0) key.append(minval) key.append(maxval) key.append(step) key.append(tuple(novalues)) key.append(address_index) key.append(shift) key.append(add) operand = OperandImmRange(name, descr, minval, maxval, step, address_index, shift, novalues, add) elif "Values" in elem: values = tuple(elem["Values"]) key.append(tuple(values)) operand = OperandValueSet(name, descr, values) elif "Value" in elem: value = elem["Value"] key.append(value) operand = OperandConst(name, descr, value) elif "Register" in elem: reg = registers[elem["Register"]] address_base = elem.get("AddressBase", False) address_index = elem.get("AddressIndex", False) floating_point = elem.get("FloatingPoint", False) vector = elem.get("Vector", False) key.append(elem["Register"]) key.append(address_base) key.append(address_index) key.append(floating_point) key.append(vector) operand = OperandConstReg(name, descr, reg, address_base, address_index, floating_point, vector) elif "Relative" in elem: mindispl = elem["MinDisplacement"] maxdispl = elem["MaxDisplacement"] relative = elem["Relative"] shift = elem.get("Shift", 0) except_ranges = elem.get("ExceptRange", []) key.append(mindispl) key.append(maxdispl) key.append(shift) key.append(tuple([tuple(elem) for elem in except_ranges])) operand = InstructionAddressRelativeOperand( name, descr, maxdispl, mindispl, shift, except_ranges, relative) else: raise MicroprobeArchitectureDefinitionError( "Operand definition '%s' in '%s' not supported" % (name, filename)) tkey = tuple(key) if tkey in operands_duplicated: LOG.warning( "Similar definition of operands: '%s' and" " '%s'. Check if definition needed.", name, operands_duplicated[tkey]) else: operands_duplicated[tkey] = name except KeyError as exception: raise MicroprobeArchitectureDefinitionError( "Definition" " of operand '%s' " "uses an unknown " "register in '%s'" "\nMissing defini" "tion of: %s" % (name, filename, exception)) if name in operands and not override: raise MicroprobeArchitectureDefinitionError( "Duplicated definition of operand '%s' found in '%s'" % (name, filename)) LOG.debug(operand) operands[name] = operand LOG.debug("End") return operands
def import_definition(cls, filenames, ifields): """ :param filenames: :param ifields: """ LOG.debug("Start") iformats = {} iformats_duplicated = {} for filename in filenames: iformat_data = read_yaml(filename, SCHEMA) if iformat_data is None: continue for elem in iformat_data: name = elem["Name"] descr = elem.get("Description", "No description") assembly = elem["Assembly"] # TODO: Document the convention nonzero_fields = [ field for field in elem["Fields"] if not field.startswith("0_") ] key = tuple([tuple(elem["Fields"]), assembly]) if key in iformats_duplicated: LOG.warning( "Similar definition of instruction format: '%s' " "and '%s'. Check if definition needed.", name, iformats_duplicated[key]) else: iformats_duplicated[key] = name if len(nonzero_fields) != len(set(nonzero_fields)): raise MicroprobeArchitectureDefinitionError( "Definition of " "instruction format" " '%s' found in '%s'" " contains duplicated" " fields." % (name, filename)) try: fields = [ifields[ifieldname] for ifieldname in elem["Fields"]] except KeyError as key: raise MicroprobeArchitectureDefinitionError( "Unknown field %s " "definition in " "instruction format" " '%s' found in '%s'." % (key, name, filename)) iformat = cls(name, descr, fields, assembly) if name in iformats: raise MicroprobeArchitectureDefinitionError("Duplicated " "definition " "of instruction " "format " "'%s' found " "in '%s'" % (name, filename)) LOG.debug(iformat) iformats[name] = iformat LOG.debug("End") return iformats
def _read_yaml_definition(isadefs, path): """ :param isadefs: :param path: """ isadef = read_yaml(os.path.join(path, "isa.yaml"), SCHEMA) isadef["Path"] = path isadefs.append(isadef) _read_isa_extensions(isadefs, path) baseisa = read_yaml(DEFAULT_ISA, SCHEMA) baseisa["Path"] = DEFAULT_ISA isadefs.append(baseisa) complete_isadef = dict2OrderedDict({}) isadefs.reverse() for isadef in isadefs: for key, val in isadef.items(): if not isinstance(val, dict): complete_isadef[key] = isadef[key] else: override = val.get("Override", False) inherit = val.get("Inherit", False) if key not in complete_isadef: complete_isadef[key] = {} for key2 in val: if key2 in ["YAML", "Modules"]: if key2 not in complete_isadef[key]: complete_isadef[key][key2] = [] if os.path.isabs(val[key2]): if override: complete_isadef[key][key2] = [val[key2]] else: complete_isadef[key][key2].append(val[key2]) else: if override: complete_isadef[key][key2] = [ os.path.join( isadef["Path"], val[key2] ) ] else: complete_isadef[key][key2].append( os.path.join( isadef["Path"], val[key2] ) ) if inherit: key3 = "%s_inherits" % key2 if key3 not in complete_isadef[key]: complete_isadef[key][key3] = [] complete_isadef[key][key3].append( complete_isadef[key][key2][-1] ) elif key2 == "Module": if val[key2].startswith("microprobe"): val[key2] = os.path.join( os.path.dirname(__file__), "..", "..", "..", val[key2] ) if os.path.isabs(val[key2]): complete_isadef[key][key2] = val[key2] else: complete_isadef[key][key2] = os.path.join( isadef["Path"], val[key2] ) else: complete_isadef[key][key2] = val[key2] return complete_isadef
def _read_yaml_definition(uarchdefs, path): """ :param uarchdefs: :param path: """ uarchdef = read_yaml(os.path.join(path, "microarchitecture.yaml"), SCHEMA) uarchdef["Path"] = path uarchdefs.append(uarchdef) _read_uarch_extensions(uarchdefs, path) baseuarch = read_yaml(DEFAULT_UARCH, SCHEMA) baseuarch["Path"] = DEFAULT_UARCH uarchdefs.append(baseuarch) complete_uarchdef = {} uarchdefs.reverse() for uarchdef in uarchdefs: for key, val in uarchdef.items(): if not isinstance(val, dict): complete_uarchdef[key] = uarchdef[key] else: override = val.get("Override", False) if key not in complete_uarchdef: complete_uarchdef[key] = {} for key2 in val: if key2 in ["YAML", "Modules", "Path"]: if key2 not in complete_uarchdef[key]: complete_uarchdef[key][key2] = [] if os.path.isabs(val[key2]): if override: complete_uarchdef[key][key2] = [val[key2]] else: complete_uarchdef[key][key2].append(val[key2]) else: if override: complete_uarchdef[key][key2] = [ os.path.join(uarchdef["Path"], val[key2]) ] else: complete_uarchdef[key][key2].append( os.path.join(uarchdef["Path"], val[key2])) elif key2 == "Module": if val[key2].startswith("microprobe"): val[key2] = os.path.join(os.path.dirname(__file__), "..", "..", "..", val[key2]) if os.path.isabs(val[key2]): complete_uarchdef[key][key2] = val[key2] else: complete_uarchdef[key][key2] = os.path.join( uarchdef["Path"], val[key2]) else: complete_uarchdef[key][key2] = val[key2] return complete_uarchdef
def import_definition(cls, filenames, element_types): """ """ LOG.debug("Start importing microarchitecture elements") elements = RejectingDict() elements_subelements = RejectingDict() for filename in filenames: element_data = read_yaml(filename, SCHEMA) if element_data is None: continue for elem in element_data: name = elem["Name"] parent = elem.get("Parent", None) subelements = elem.get("Subelements", []) repeat = elem.get("Repeat", None) rfrom = 0 rto = 0 replace = "0" try: elem_type = element_types[elem["Type"]] except KeyError: raise MicroprobeArchitectureDefinitionError( "Unknown " "microarchitecture element type in " "microarchitecture element definition " " '%s' found in '%s'" % (name, filename)) descr = elem.get("Description", elem_type.description) if repeat: rfrom = repeat["From"] replace = "%s" % rfrom rto = repeat["To"] for index in range(rfrom, rto + 1): cname = name.replace(replace, "%d" % index) cdescr = descr.replace(replace, "%d" % index) element = cls(cname, cdescr, elem_type) try: elements[cname] = element elements_subelements[cname] = subelements except ValueError: raise MicroprobeArchitectureDefinitionError( "Duplicated microarchitecture element " "definition '%s' found in '%s'" % (name, filename)) LOG.debug(element) for filename in filenames: import_properties(filename, elements) for elem, subelements in elements_subelements.items(): try: subelements_instances = [elements[item] for item in subelements] except KeyError as exc: raise MicroprobeArchitectureDefinitionError( "Undefined sub-element '%s' in element " "definition '%s'. Check following " "files: %s" % (exc, elem, filenames)) elements[elem].set_subelements(subelements_instances) element_list = list(elements.values()) fixing_hierarchy = True LOG.info("Start building element hierarchy...") fix_pass = 0 while fixing_hierarchy: fix_pass += 1 LOG.debug("Start building element hierarchy... pass %d", fix_pass) fixing_hierarchy = False for element in element_list: parents = [ item for item in element_list if element in item.subelements ] if len(parents) > 1: # needs duplication LOG.debug("Element %s has %d parents", element, len(parents)) for parent in sorted(parents): LOG.debug("Duplicating for parent: %s", parent) # Create a new copy new_element = cls(element.name, element.description, element.type) new_element.set_subelements(element.subelements) element_list.append(new_element) # Update parent to point to the new copy new_subelements = parent.subelements new_subelements.remove(element) new_subelements.append(new_element) parent.set_subelements(new_subelements) fixing_hierarchy = True element_list.remove(element) LOG.info("Finish building element hierarchy") # Check correctness of the structure and set parents LOG.info("Checking element hierarchy...") top_element = None for element in element_list: parents = [ item for item in element_list if element in item.subelements ] if len(parents) > 1: raise MicroprobeArchitectureDefinitionError( "Wrong hierarchy of microarchitecture " "elements. The definition of element" " '%s' has multiple parents: '%s'." % (element, [str(elem) for elem in parents])) elif len(parents) == 0: if top_element is not None: raise MicroprobeArchitectureDefinitionError( "Wrong hierarchy of microarchitecture " "elements. There are at least two top " "elements: '%s' and '%s'. Define a single " "parent element for all the hierarchy." % (element, top_element)) top_element = element else: element.set_parent_element(parents[0]) if top_element is None: raise MicroprobeArchitectureDefinitionError( "Wrong hierarchy of microarchitecture " "elements. There is not a top element." " Define a single parent element for all " "the hierarchy.") LOG.info("Element hierarchy correct") elem_dict = dict([(element.full_name, element) for element in element_list]) for filename in filenames: import_properties(filename, elem_dict) LOG.info("End importing elements") return elem_dict