micro_asm.py
来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· Python 代码 · 共 503 行
PY
503 行
# Copyright (c) 2003, 2004, 2005# The Regents of The University of Michigan# All Rights Reserved## This code is part of the M5 simulator.## Permission is granted to use, copy, create derivative works and# redistribute this software and such derivative works for any# purpose, so long as the copyright notice above, this grant of# permission, and the disclaimer below appear in all copies made; and# so long as the name of The University of Michigan is not used in any# advertising or publicity pertaining to the use or distribution of# this software without specific, written prior authorization.## THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE# UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND# WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER# EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR# PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE# LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT,# INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM# ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN# IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH# DAMAGES.## Authors: Gabe Black#import osimport sysimport reimport stringimport traceback# get type namesfrom types import *# Prepend the directory where the PLY lex & yacc modules are found# to the search path.sys.path[0:0] = [os.environ['M5_PLY']]from ply import lexfrom ply import yacc############################################################################ Base classes for use outside of the assembler###########################################################################class Micro_Container(object): def __init__(self, name): self.microops = [] self.name = name self.directives = {} self.micro_classes = {} self.labels = {} def add_microop(self, mnemonic, microop): self.microops.append(microop) def __str__(self): string = "%s:\n" % self.name for microop in self.microops: string += " %s\n" % microop return stringclass Combinational_Macroop(Micro_Container): passclass Rom_Macroop(object): def __init__(self, name, target): self.name = name self.target = target def __str__(self): return "%s: %s\n" % (self.name, self.target)class Rom(Micro_Container): def __init__(self, name): super(Rom, self).__init__(name) self.externs = {}############################################################################ Support classes###########################################################################class Label(object): def __init__(self): self.extern = False self.name = ""class Block(object): def __init__(self): self.statements = []class Statement(object): def __init__(self): self.is_microop = False self.is_directive = False self.params = ""class Microop(Statement): def __init__(self): super(Microop, self).__init__() self.mnemonic = "" self.labels = [] self.is_microop = Trueclass Directive(Statement): def __init__(self): super(Directive, self).__init__() self.name = "" self.is_directive = True############################################################################ Functions that handle common tasks###########################################################################def print_error(message): print print "*** %s" % message printdef handle_statement(parser, container, statement): if statement.is_microop: if statement.mnemonic not in parser.microops.keys(): raise Exception, "Unrecognized mnemonic: %s" % statement.mnemonic parser.symbols["__microopClassFromInsideTheAssembler"] = \ parser.microops[statement.mnemonic] try: microop = eval('__microopClassFromInsideTheAssembler(%s)' % statement.params, {}, parser.symbols) except: print_error("Error creating microop object with mnemonic %s." % \ statement.mnemonic) raise try: for label in statement.labels: container.labels[label.text] = microop if label.extern: container.externs[label.text] = microop container.add_microop(statement.mnemonic, microop) except: print_error("Error adding microop.") raise elif statement.is_directive: if statement.name not in container.directives.keys(): raise Exception, "Unrecognized directive: %s" % statement.name parser.symbols["__directiveFunctionFromInsideTheAssembler"] = \ container.directives[statement.name] try: eval('__directiveFunctionFromInsideTheAssembler(%s)' % statement.params, {}, parser.symbols) except: print_error("Error executing directive.") print container.directives raise else: raise Exception, "Didn't recognize the type of statement", statement############################################################################ Lexer specification############################################################################ 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): # 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("%s %s" % (line_str, string))reserved = ('DEF', 'MACROOP', 'ROM', 'EXTERN')tokens = reserved + ( # identifier 'ID', # arguments for microops and directives 'PARAMS', 'LPAREN', 'RPAREN', 'LBRACE', 'RBRACE', 'COLON', 'SEMI', 'DOT', 'NEWLINE' )# New lines are ignored at the top level, but they end statements in the# assemblerstates = ( ('asm', 'exclusive'), ('params', 'exclusive'),)reserved_map = { }for r in reserved: reserved_map[r.lower()] = r# Ignore commentsdef t_ANY_COMMENT(t): r'\#[^\n]*(?=\n)'def t_ANY_MULTILINECOMMENT(t): r'/\*([^/]|((?<!\*)/))*\*/'# A colon marks the end of a label. It should follow an ID which will# put the lexer in the "params" state. Seeing the colon will put it back# in the "asm" state since it knows it saw a label and not a mnemonic.def t_params_COLON(t): r':' t.lexer.begin('asm') return t# Parameters are a string of text which don't contain an unescaped statement# statement terminator, ie a newline or semi colon.def t_params_PARAMS(t): r'([^\n;\\]|(\\[\n;\\]))+' t.lineno += t.value.count('\n') unescapeParamsRE = re.compile(r'(\\[\n;\\])') def unescapeParams(mo): val = mo.group(0) return val[1] t.value = unescapeParamsRE.sub(unescapeParams, t.value) t.lexer.begin('asm') return t# An "ID" in the micro assembler is either a label, directive, or mnemonic# If it's either a directive or a mnemonic, it will be optionally followed by# parameters. If it's a label, the following colon will make the lexer stop# looking for parameters.def t_asm_ID(t): r'[A-Za-z_]\w*' t.type = reserved_map.get(t.value, 'ID') t.lexer.begin('params') return t# If there is a label and you're -not- in the assembler (which would be caught# above), don't start looking for parameters.def t_ANY_ID(t): r'[A-Za-z_]\w*' t.type = reserved_map.get(t.value, 'ID') return t# Braces enter and exit micro assemblydef t_INITIAL_LBRACE(t): r'\{' t.lexer.begin('asm') return tdef t_asm_RBRACE(t): r'\}' t.lexer.begin('INITIAL') return t# At the top level, keep track of newlines only for line counting.def t_INITIAL_NEWLINE(t): r'\n+' t.lineno += t.value.count('\n')# In the micro assembler, do line counting but also return a token. The# token is needed by the parser to detect the end of a statement.def t_asm_NEWLINE(t): r'\n+' t.lineno += t.value.count('\n') return t# A newline or semi colon when looking for params signals that the statement# is over and the lexer should go back to looking for regular assembly.def t_params_NEWLINE(t): r'\n+' t.lineno += t.value.count('\n') t.lexer.begin('asm') return tdef t_params_SEMI(t): r';' t.lexer.begin('asm') return t# Basic regular expressions to pick out simple tokenst_ANY_LPAREN = r'\('t_ANY_RPAREN = r'\)'t_ANY_SEMI = r';'t_ANY_DOT = r'\.'t_ANY_ignore = ' \t\x0c'def t_ANY_error(t): error(t.lineno, "illegal character '%s'" % t.value[0]) t.skip(1)############################################################################ Parser specification############################################################################ Start symbol for a file which may have more than one macroop or rom# specification.def p_file(t): 'file : opt_rom_or_macros'def p_opt_rom_or_macros_0(t): 'opt_rom_or_macros : 'def p_opt_rom_or_macros_1(t): 'opt_rom_or_macros : rom_or_macros'def p_rom_or_macros_0(t): 'rom_or_macros : rom_or_macro'def p_rom_or_macros_1(t): 'rom_or_macros : rom_or_macros rom_or_macro'def p_rom_or_macro_0(t): '''rom_or_macro : rom_block | macroop_def'''# Defines a section of microcode that should go in the current ROMdef p_rom_block(t): 'rom_block : DEF ROM block SEMI' if not t.parser.rom: print_error("Rom block found, but no Rom object specified.") raise TypeError, "Rom block found, but no Rom object was specified." for statement in t[3].statements: handle_statement(t.parser, t.parser.rom, statement) t[0] = t.parser.rom# Defines a macroop that jumps to an external label in the ROMdef p_macroop_def_0(t): 'macroop_def : DEF MACROOP ID LPAREN ID RPAREN SEMI' if not t.parser.rom_macroop_type: print_error("ROM based macroop found, but no ROM macroop class was specified.") raise TypeError, "ROM based macroop found, but no ROM macroop class was specified." macroop = t.parser.rom_macroop_type(t[3], t[5]) t.parser.macroops[t[3]] = macroop# Defines a macroop that is combinationally generateddef p_macroop_def_1(t): 'macroop_def : DEF MACROOP ID block SEMI' try: curop = t.parser.macro_type(t[3]) except TypeError: print_error("Error creating macroop object.") raise for statement in t[4].statements: handle_statement(t.parser, curop, statement) t.parser.macroops[t[3]] = curop# A block of statementsdef p_block(t): 'block : LBRACE statements RBRACE' block = Block() block.statements = t[2] t[0] = blockdef p_statements_0(t): 'statements : statement' if t[1]: t[0] = [t[1]] else: t[0] = []def p_statements_1(t): 'statements : statements statement' if t[2]: t[1].append(t[2]) t[0] = t[1]def p_statement(t): 'statement : content_of_statement end_of_statement' t[0] = t[1]# A statement can be a microop or an assembler directivedef p_content_of_statement_0(t): '''content_of_statement : microop | directive''' t[0] = t[1]# Ignore empty statementsdef p_content_of_statement_1(t): 'content_of_statement : ' pass# Statements are ended by newlines or a semi colondef p_end_of_statement(t): '''end_of_statement : NEWLINE | SEMI''' pass# Different flavors of microop to avoid shift/reduce errorsdef p_microop_0(t): 'microop : labels ID' microop = Microop() microop.labels = t[1] microop.mnemonic = t[2] t[0] = microopdef p_microop_1(t): 'microop : ID' microop = Microop() microop.mnemonic = t[1] t[0] = microopdef p_microop_2(t): 'microop : labels ID PARAMS' microop = Microop() microop.labels = t[1] microop.mnemonic = t[2] microop.params = t[3] t[0] = microopdef p_microop_3(t): 'microop : ID PARAMS' microop = Microop() microop.mnemonic = t[1] microop.params = t[2] t[0] = microop# Labels in the microcodedef p_labels_0(t): 'labels : label' t[0] = [t[1]]def p_labels_1(t): 'labels : labels label' t[1].append(t[2]) t[0] = t[1]# labels on lines by themselves are attached to the following instruction.def p_labels_2(t): 'labels : labels NEWLINE' t[0] = t[1]def p_label_0(t): 'label : ID COLON' label = Label() label.is_extern = False label.text = t[1] t[0] = labeldef p_label_1(t): 'label : EXTERN ID COLON' label = Label() label.is_extern = True label.text = t[2] t[0] = label# Directives for the macroopdef p_directive_0(t): 'directive : DOT ID' directive = Directive() directive.name = t[2] t[0] = directivedef p_directive_1(t): 'directive : DOT ID PARAMS' directive = Directive() directive.name = t[2] directive.params = t[3] t[0] = directive# 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.lineno, "syntax error at '%s'" % t.value) else: error(0, "unknown syntax error", True)class MicroAssembler(object): def __init__(self, macro_type, microops, rom = None, rom_macroop_type = None): self.lexer = lex.lex() self.parser = yacc.yacc() self.parser.macro_type = macro_type self.parser.macroops = {} self.parser.microops = microops self.parser.rom = rom self.parser.rom_macroop_type = rom_macroop_type self.parser.symbols = {} self.symbols = self.parser.symbols def assemble(self, asm): self.parser.parse(asm, lexer=self.lexer) macroops = self.parser.macroops self.parser.macroops = {} return macroops
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?