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