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 + -
显示快捷键?