isa_parser.py

来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· Python 代码 · 共 1,867 行 · 第 1/5 页

PY
1,867
字号
    for cpu in cpu_models:        result[cpu.name] = t % cpu.strings    return result# *If* the template has CPU-specific references, return a single# string containing a copy of the template for each CPU model with the# corresponding values substituted in.  If the template has no# CPU-specific references, it is returned unmodified.def expand_cpu_symbols_to_string(template):    if template.find('%(CPU_') != -1:        return reduce(lambda x,y: x+y,                      expand_cpu_symbols_to_dict(template).values())    else:        return template# Protect CPU-specific references by doubling the corresponding '%'s# (in preparation for substituting a different set of references into# the template).def protect_cpu_symbols(template):    return re.sub(r'%(?=\(CPU_)', '%%', template)################ GenCode class## The GenCode class encapsulates generated code destined for various# output files.  The header_output and decoder_output attributes are# strings containing code destined for decoder.hh and decoder.cc# respectively.  The decode_block attribute contains code to be# incorporated in the decode function itself (that will also end up in# decoder.cc).  The exec_output attribute is a dictionary with a key# for each CPU model name; the value associated with a particular key# is the string of code for that CPU model's exec.cc file.  The# has_decode_default attribute is used in the decode block to allow# explicit default clauses to override default default clauses.class GenCode:    # Constructor.  At this point we substitute out all CPU-specific    # symbols.  For the exec output, these go into the per-model    # dictionary.  For all other output types they get collapsed into    # a single string.    def __init__(self,                 header_output = '', decoder_output = '', exec_output = '',                 decode_block = '', has_decode_default = False):        self.header_output = expand_cpu_symbols_to_string(header_output)        self.decoder_output = expand_cpu_symbols_to_string(decoder_output)        if isinstance(exec_output, dict):            self.exec_output = exec_output        elif isinstance(exec_output, str):            # If the exec_output arg is a single string, we replicate            # it for each of the CPU models, substituting and            # %(CPU_foo)s params appropriately.            self.exec_output = expand_cpu_symbols_to_dict(exec_output)        self.decode_block = expand_cpu_symbols_to_string(decode_block)        self.has_decode_default = has_decode_default    # Override '+' operator: generate a new GenCode object that    # concatenates all the individual strings in the operands.    def __add__(self, other):        exec_output = {}        for cpu in cpu_models:            n = cpu.name            exec_output[n] = self.exec_output[n] + other.exec_output[n]        return GenCode(self.header_output + other.header_output,                       self.decoder_output + other.decoder_output,                       exec_output,                       self.decode_block + other.decode_block,                       self.has_decode_default or other.has_decode_default)    # Prepend a string (typically a comment) to all the strings.    def prepend_all(self, pre):        self.header_output = pre + self.header_output        self.decoder_output  = pre + self.decoder_output        self.decode_block = pre + self.decode_block        for cpu in cpu_models:            self.exec_output[cpu.name] = pre + self.exec_output[cpu.name]    # Wrap the decode block in a pair of strings (e.g., 'case foo:'    # and 'break;').  Used to build the big nested switch statement.    def wrap_decode_block(self, pre, post = ''):        self.decode_block = pre + indent(self.decode_block) + post################# Format object.## A format object encapsulates an instruction format.  It must provide# a defineInst() method that generates the code for an instruction# definition.exportContextSymbols = ('InstObjParams', 'makeList', 're', 'string')exportContext = {}def updateExportContext():    exportContext.update(exportDict(*exportContextSymbols))    exportContext.update(templateMap)def exportDict(*symNames):    return dict([(s, eval(s)) for s in symNames])class Format:    def __init__(self, id, params, code):        # constructor: just save away arguments        self.id = id        self.params = params        label = 'def format ' + id        self.user_code = compile(fixPythonIndentation(code), label, 'exec')        param_list = string.join(params, ", ")        f = '''def defInst(_code, _context, %s):                my_locals = vars().copy()                exec _code in _context, my_locals                return my_locals\n''' % param_list        c = compile(f, label + ' wrapper', 'exec')        exec c        self.func = defInst    def defineInst(self, name, args, lineno):        context = {}        updateExportContext()        context.update(exportContext)        if len(name):            Name = name[0].upper()            if len(name) > 1:                Name += name[1:]        context.update({ 'name': name, 'Name': Name })        try:            vars = self.func(self.user_code, context, *args[0], **args[1])        except Exception, exc:            error(lineno, 'error defining "%s": %s.' % (name, exc))        for k in vars.keys():            if k not in ('header_output', 'decoder_output',                         'exec_output', 'decode_block'):                del vars[k]        return GenCode(**vars)# Special null format to catch an implicit-format instruction# definition outside of any format block.class NoFormat:    def __init__(self):        self.defaultInst = ''    def defineInst(self, name, args, lineno):        error(lineno,              'instruction definition "%s" with no active format!' % name)# This dictionary maps format name strings to Format objects.formatMap = {}# Define a new formatdef defFormat(id, params, code, lineno):    # make sure we haven't already defined this one    if formatMap.get(id, None) != None:        error(lineno, 'format %s redefined.' % id)    # create new object and store in global map    formatMap[id] = Format(id, params, code)############### Stack: a simple stack object.  Used for both formats (formatStack)# and default cases (defaultStack).  Simply wraps a list to give more# stack-like syntax and enable initialization with an argument list# (as opposed to an argument that's a list).class Stack(list):    def __init__(self, *items):        list.__init__(self, items)    def push(self, item):        self.append(item);    def top(self):        return self[-1]# The global format stack.formatStack = Stack(NoFormat())# The global default case stack.defaultStack = Stack( None )# Global stack that tracks current file and line number.# Each element is a tuple (filename, lineno) that records the# *current* filename and the line number in the *previous* file where# it was included.fileNameStack = Stack()#################### Utility functions## Indent every line in string 's' by two spaces# (except preprocessor directives).# Used to make nested code blocks look pretty.#def indent(s):    return re.sub(r'(?m)^(?!#)', '  ', s)## Munge a somewhat arbitrarily formatted piece of Python code# (e.g. from a format 'let' block) into something whose indentation# will get by the Python parser.## The two keys here are that Python will give a syntax error if# there's any whitespace at the beginning of the first line, and that# all lines at the same lexical nesting level must have identical# indentation.  Unfortunately the way code literals work, an entire# let block tends to have some initial indentation.  Rather than# trying to figure out what that is and strip it off, we prepend 'if# 1:' to make the let code the nested block inside the if (and have# the parser automatically deal with the indentation for us).## We don't want to do this if (1) the code block is empty or (2) the# first line of the block doesn't have any whitespace at the front.def fixPythonIndentation(s):    # get rid of blank lines first    s = re.sub(r'(?m)^\s*\n', '', s);    if (s != '' and re.match(r'[ \t]', s[0])):        s = 'if 1:\n' + s    return s# Error handler.  Just call exit.  Output formatted to work under# Emacs compile-mode.  Optional 'print_traceback' arg, if set to True,# prints a Python stack backtrace too (can be handy when trying to# debug the parser itself).def error(lineno, string, print_traceback = False):    spaces = ""    for (filename, line) in fileNameStack[0:-1]:        print spaces + "In file included from " + filename + ":"        spaces += "  "    # Print a Python stack backtrace if requested.    if (print_traceback):        traceback.print_exc()    if lineno != 0:        line_str = "%d:" % lineno    else:        line_str = ""    sys.exit(spaces + "%s:%s %s" % (fileNameStack[-1][0], line_str, string))#######################################################################                      Bitfield Operator Support######################################################################bitOp1ArgRE = re.compile(r'<\s*(\w+)\s*:\s*>')bitOpWordRE = re.compile(r'(?<![\w\.])([\w\.]+)<\s*(\w+)\s*:\s*(\w+)\s*>')bitOpExprRE = re.compile(r'\)<\s*(\w+)\s*:\s*(\w+)\s*>')def substBitOps(code):    # first convert single-bit selectors to two-index form    # i.e., <n> --> <n:n>    code = bitOp1ArgRE.sub(r'<\1:\1>', code)    # simple case: selector applied to ID (name)    # i.e., foo<a:b> --> bits(foo, a, b)    code = bitOpWordRE.sub(r'bits(\1, \2, \3)', code)    # if selector is applied to expression (ending in ')'),    # we need to search backward for matching '('    match = bitOpExprRE.search(code)    while match:        exprEnd = match.start()        here = exprEnd - 1        nestLevel = 1        while nestLevel > 0:            if code[here] == '(':                nestLevel -= 1            elif code[here] == ')':                nestLevel += 1            here -= 1            if here < 0:                sys.exit("Didn't find '('!")        exprStart = here+1        newExpr = r'bits(%s, %s, %s)' % (code[exprStart:exprEnd+1],                                         match.group(1), match.group(2))        code = code[:exprStart] + newExpr + code[match.end():]        match = bitOpExprRE.search(code)    return code##################### Template objects.## Template objects are format strings that allow substitution from# the attribute spaces of other objects (e.g. InstObjParams instances).labelRE = re.compile(r'(?<!%)%\(([^\)]+)\)[sd]')class Template:    def __init__(self, t):        self.template = t    def subst(self, d):        myDict = None        # Protect non-Python-dict substitutions (e.g. if there's a printf        # in the templated C++ code)        template = protect_non_subst_percents(self.template)        # CPU-model-specific substitutions are handled later (in GenCode).        template = protect_cpu_symbols(template)        # Build a dict ('myDict') to use for the template substitution.        # Start with the template namespace.  Make a copy since we're        # going to modify it.        myDict = templateMap.copy()        if isinstance(d, InstObjParams):            # If we're dealing with an InstObjParams object, we need            # to be a little more sophisticated.  The instruction-wide            # parameters are already formed, but the parameters which            # are only function wide still need to be generated.            compositeCode = ''            myDict.update(d.__dict__)            # The "operands" and "snippets" attributes of the InstObjParams            # objects are for internal use and not substitution.            del myDict['operands']            del myDict['snippets']            snippetLabels = [l for l in labelRE.findall(template)                             if d.snippets.has_key(l)]            snippets = dict([(s, mungeSnippet(d.snippets[s]))                             for s in snippetLabels])            myDict.update(snippets)            compositeCode = ' '.join(map(str, snippets.values()))            # Add in template itself in case it references any            # operands explicitly (like Mem)            compositeCode += ' ' + template            operands = SubOperandList(compositeCode, d.operands)            myDict['op_decl'] = operands.concatAttrStrings('op_decl')            is_src = lambda op: op.is_src            is_dest = lambda op: op.is_dest            myDict['op_src_decl'] = \                      operands.concatSomeAttrStrings(is_src, 'op_src_decl')            myDict['op_dest_decl'] = \                      operands.concatSomeAttrStrings(is_dest, 'op_dest_decl')            myDict['op_rd'] = operands.concatAttrStrings('op_rd')            myDict['op_wb'] = operands.concatAttrStrings('op_wb')            if d.operands.memOperand:                myDict['mem_acc_size'] = d.operands.memOperand.mem_acc_size                myDict['mem_acc_type'] = d.operands.memOperand.mem_acc_type        elif isinstance(d, dict):            # if the argument is a dictionary, we just use it.            myDict.update(d)        elif hasattr(d, '__dict__'):            # if the argument is an object, we use its attribute map.            myDict.update(d.__dict__)        else:            raise TypeError, "Template.subst() arg must be or have dictionary"        return template % myDict    # Convert to string.  This handles the case when a template with a    # CPU-specific term gets interpolated into another template or into    # an output block.    def __str__(self):        return expand_cpu_symbols_to_string(self.template)#######################################################################                             Code Parser## The remaining code is the support for automatically extracting# instruction characteristics from pseudocode.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?