isa_parser.py

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

PY
1,867
字号
# alternate form for structure member: 'def bitfield <ID> <ID>'def p_def_bitfield_struct(t):    'def_bitfield_struct : DEF opt_signed BITFIELD ID id_with_dot SEMI'    if (t[2] != ''):        error(t.lexer.lineno, 'error: structure bitfields are always unsigned.')    expr = 'machInst.%s' % t[5]    hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)    t[0] = GenCode(header_output = hash_define)def p_id_with_dot_0(t):    'id_with_dot : ID'    t[0] = t[1]def p_id_with_dot_1(t):    'id_with_dot : ID DOT id_with_dot'    t[0] = t[1] + t[2] + t[3]def p_opt_signed_0(t):    'opt_signed : SIGNED'    t[0] = t[1]def p_opt_signed_1(t):    'opt_signed : empty'    t[0] = ''# Global map variable to hold templatestemplateMap = {}def p_def_template(t):    'def_template : DEF TEMPLATE ID CODELIT SEMI'    templateMap[t[3]] = Template(t[4])    t[0] = GenCode()# An instruction format definition looks like# "def format <fmt>(<params>) {{...}};"def p_def_format(t):    'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI'    (id, params, code) = (t[3], t[5], t[7])    defFormat(id, params, code, t.lexer.lineno)    t[0] = GenCode()# The formal parameter list for an instruction format is a possibly# empty list of comma-separated parameters.  Positional (standard,# non-keyword) parameters must come first, followed by keyword# parameters, followed by a '*foo' parameter that gets excess# positional arguments (as in Python).  Each of these three parameter# categories is optional.## Note that we do not support the '**foo' parameter for collecting# otherwise undefined keyword args.  Otherwise the parameter list is# (I believe) identical to what is supported in Python.## The param list generates a tuple, where the first element is a list of# the positional params and the second element is a dict containing the# keyword params.def p_param_list_0(t):    'param_list : positional_param_list COMMA nonpositional_param_list'    t[0] = t[1] + t[3]def p_param_list_1(t):    '''param_list : positional_param_list                  | nonpositional_param_list'''    t[0] = t[1]def p_positional_param_list_0(t):    'positional_param_list : empty'    t[0] = []def p_positional_param_list_1(t):    'positional_param_list : ID'    t[0] = [t[1]]def p_positional_param_list_2(t):    'positional_param_list : positional_param_list COMMA ID'    t[0] = t[1] + [t[3]]def p_nonpositional_param_list_0(t):    'nonpositional_param_list : keyword_param_list COMMA excess_args_param'    t[0] = t[1] + t[3]def p_nonpositional_param_list_1(t):    '''nonpositional_param_list : keyword_param_list                                | excess_args_param'''    t[0] = t[1]def p_keyword_param_list_0(t):    'keyword_param_list : keyword_param'    t[0] = [t[1]]def p_keyword_param_list_1(t):    'keyword_param_list : keyword_param_list COMMA keyword_param'    t[0] = t[1] + [t[3]]def p_keyword_param(t):    'keyword_param : ID EQUALS expr'    t[0] = t[1] + ' = ' + t[3].__repr__()def p_excess_args_param(t):    'excess_args_param : ASTERISK ID'    # Just concatenate them: '*ID'.  Wrap in list to be consistent    # with positional_param_list and keyword_param_list.    t[0] = [t[1] + t[2]]# End of format definition-related rules.################ A decode block looks like:#	decode <field1> [, <field2>]* [default <inst>] { ... }#def p_decode_block(t):    'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE'    default_defaults = defaultStack.pop()    codeObj = t[5]    # use the "default defaults" only if there was no explicit    # default statement in decode_stmt_list    if not codeObj.has_decode_default:        codeObj += default_defaults    codeObj.wrap_decode_block('switch (%s) {\n' % t[2], '}\n')    t[0] = codeObj# The opt_default statement serves only to push the "default defaults"# onto defaultStack.  This value will be used by nested decode blocks,# and used and popped off when the current decode_block is processed# (in p_decode_block() above).def p_opt_default_0(t):    'opt_default : empty'    # no default specified: reuse the one currently at the top of the stack    defaultStack.push(defaultStack.top())    # no meaningful value returned    t[0] = Nonedef p_opt_default_1(t):    'opt_default : DEFAULT inst'    # push the new default    codeObj = t[2]    codeObj.wrap_decode_block('\ndefault:\n', 'break;\n')    defaultStack.push(codeObj)    # no meaningful value returned    t[0] = Nonedef p_decode_stmt_list_0(t):    'decode_stmt_list : decode_stmt'    t[0] = t[1]def p_decode_stmt_list_1(t):    'decode_stmt_list : decode_stmt decode_stmt_list'    if (t[1].has_decode_default and t[2].has_decode_default):        error(t.lexer.lineno, 'Two default cases in decode block')    t[0] = t[1] + t[2]## Decode statement rules## There are four types of statements allowed in a decode block:# 1. Format blocks 'format <foo> { ... }'# 2. Nested decode blocks# 3. Instruction definitions.# 4. C preprocessor directives.# Preprocessor directives found in a decode statement list are passed# through to the output, replicated to all of the output code# streams.  This works well for ifdefs, so we can ifdef out both the# declarations and the decode cases generated by an instruction# definition.  Handling them as part of the grammar makes it easy to# keep them in the right place with respect to the code generated by# the other statements.def p_decode_stmt_cpp(t):    'decode_stmt : CPPDIRECTIVE'    t[0] = GenCode(t[1], t[1], t[1], t[1])# A format block 'format <foo> { ... }' sets the default instruction# format used to handle instruction definitions inside the block.# This format can be overridden by using an explicit format on the# instruction definition or with a nested format block.def p_decode_stmt_format(t):    'decode_stmt : FORMAT push_format_id LBRACE decode_stmt_list RBRACE'    # The format will be pushed on the stack when 'push_format_id' is    # processed (see below).  Once the parser has recognized the full    # production (though the right brace), we're done with the format,    # so now we can pop it.    formatStack.pop()    t[0] = t[4]# This rule exists so we can set the current format (& push the stack)# when we recognize the format name part of the format block.def p_push_format_id(t):    'push_format_id : ID'    try:        formatStack.push(formatMap[t[1]])        t[0] = ('', '// format %s' % t[1])    except KeyError:        error(t.lexer.lineno, 'instruction format "%s" not defined.' % t[1])# Nested decode block: if the value of the current field matches the# specified constant, do a nested decode on some other field.def p_decode_stmt_decode(t):    'decode_stmt : case_label COLON decode_block'    label = t[1]    codeObj = t[3]    # just wrap the decoding code from the block as a case in the    # outer switch statement.    codeObj.wrap_decode_block('\n%s:\n' % label)    codeObj.has_decode_default = (label == 'default')    t[0] = codeObj# Instruction definition (finally!).def p_decode_stmt_inst(t):    'decode_stmt : case_label COLON inst SEMI'    label = t[1]    codeObj = t[3]    codeObj.wrap_decode_block('\n%s:' % label, 'break;\n')    codeObj.has_decode_default = (label == 'default')    t[0] = codeObj# The case label is either a list of one or more constants or 'default'def p_case_label_0(t):    'case_label : intlit_list'    t[0] = ': '.join(map(lambda a: 'case %#x' % a, t[1]))def p_case_label_1(t):    'case_label : DEFAULT'    t[0] = 'default'## The constant list for a decode case label must be non-empty, but may have# one or more comma-separated integer literals in it.#def p_intlit_list_0(t):    'intlit_list : INTLIT'    t[0] = [t[1]]def p_intlit_list_1(t):    'intlit_list : intlit_list COMMA INTLIT'    t[0] = t[1]    t[0].append(t[3])# Define an instruction using the current instruction format (specified# by an enclosing format block).# "<mnemonic>(<args>)"def p_inst_0(t):    'inst : ID LPAREN arg_list RPAREN'    # Pass the ID and arg list to the current format class to deal with.    currentFormat = formatStack.top()    codeObj = currentFormat.defineInst(t[1], t[3], t.lexer.lineno)    args = ','.join(map(str, t[3]))    args = re.sub('(?m)^', '//', args)    args = re.sub('^//', '', args)    comment = '\n// %s::%s(%s)\n' % (currentFormat.id, t[1], args)    codeObj.prepend_all(comment)    t[0] = codeObj# Define an instruction using an explicitly specified format:# "<fmt>::<mnemonic>(<args>)"def p_inst_1(t):    'inst : ID DBLCOLON ID LPAREN arg_list RPAREN'    try:        format = formatMap[t[1]]    except KeyError:        error(t.lexer.lineno, 'instruction format "%s" not defined.' % t[1])    codeObj = format.defineInst(t[3], t[5], t.lexer.lineno)    comment = '\n// %s::%s(%s)\n' % (t[1], t[3], t[5])    codeObj.prepend_all(comment)    t[0] = codeObj# The arg list generates a tuple, where the first element is a list of# the positional args and the second element is a dict containing the# keyword args.def p_arg_list_0(t):    'arg_list : positional_arg_list COMMA keyword_arg_list'    t[0] = ( t[1], t[3] )def p_arg_list_1(t):    'arg_list : positional_arg_list'    t[0] = ( t[1], {} )def p_arg_list_2(t):    'arg_list : keyword_arg_list'    t[0] = ( [], t[1] )def p_positional_arg_list_0(t):    'positional_arg_list : empty'    t[0] = []def p_positional_arg_list_1(t):    'positional_arg_list : expr'    t[0] = [t[1]]def p_positional_arg_list_2(t):    'positional_arg_list : positional_arg_list COMMA expr'    t[0] = t[1] + [t[3]]def p_keyword_arg_list_0(t):    'keyword_arg_list : keyword_arg'    t[0] = t[1]def p_keyword_arg_list_1(t):    'keyword_arg_list : keyword_arg_list COMMA keyword_arg'    t[0] = t[1]    t[0].update(t[3])def p_keyword_arg(t):    'keyword_arg : ID EQUALS expr'    t[0] = { t[1] : t[3] }## Basic expressions.  These constitute the argument values of# "function calls" (i.e. instruction definitions in the decode block)# and default values for formal parameters of format functions.## Right now, these are either strings, integers, or (recursively)# lists of exprs (using Python square-bracket list syntax).  Note that# bare identifiers are trated as string constants here (since there# isn't really a variable namespace to refer to).#def p_expr_0(t):    '''expr : ID            | INTLIT            | STRLIT            | CODELIT'''    t[0] = t[1]def p_expr_1(t):    '''expr : LBRACKET list_expr RBRACKET'''    t[0] = t[2]def p_list_expr_0(t):    'list_expr : expr'    t[0] = [t[1]]def p_list_expr_1(t):    'list_expr : list_expr COMMA expr'    t[0] = t[1] + [t[3]]def p_list_expr_2(t):    'list_expr : empty'    t[0] = []## Empty production... use in other rules for readability.#def p_empty(t):    'empty :'    pass# Parse error handler.  Note that the argument here is the offending# *token*, not a grammar symbol (hence the need to use t.value)def p_error(t):    if t:        error(t.lexer.lineno, "syntax error at '%s'" % t.value)    else:        error(0, "unknown syntax error", True)# END OF GRAMMAR RULES## Now build the parser.parser = yacc.yacc()#######################################################################                           Support Classes####################################################################### Expand template with CPU-specific references into a dictionary with# an entry for each CPU model name.  The entry key is the model name# and the corresponding value is the template with the CPU-specific# refs substituted for that model.def expand_cpu_symbols_to_dict(template):    # Protect '%'s that don't go with CPU-specific terms    t = re.sub(r'%(?!\(CPU_)', '%%', template)    result = {}

⌨️ 快捷键说明

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