micro_asm.py revision 5009
14483Sgblack@eecs.umich.edu# Copyright (c) 2003-2005 The Regents of The University of Michigan
24483Sgblack@eecs.umich.edu# All rights reserved.
34483Sgblack@eecs.umich.edu#
44483Sgblack@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
54483Sgblack@eecs.umich.edu# modification, are permitted provided that the following conditions are
64483Sgblack@eecs.umich.edu# met: redistributions of source code must retain the above copyright
74483Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
84483Sgblack@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
94483Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
104483Sgblack@eecs.umich.edu# documentation and/or other materials provided with the distribution;
114483Sgblack@eecs.umich.edu# neither the name of the copyright holders nor the names of its
124483Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from
134483Sgblack@eecs.umich.edu# this software without specific prior written permission.
144483Sgblack@eecs.umich.edu#
154483Sgblack@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
164483Sgblack@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
174483Sgblack@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
184483Sgblack@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
194483Sgblack@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
204483Sgblack@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
214483Sgblack@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
224483Sgblack@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
234483Sgblack@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
244483Sgblack@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
254483Sgblack@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
264483Sgblack@eecs.umich.edu#
274483Sgblack@eecs.umich.edu# Authors: Gabe Black
284483Sgblack@eecs.umich.edu
294483Sgblack@eecs.umich.eduimport os
304483Sgblack@eecs.umich.eduimport sys
314483Sgblack@eecs.umich.eduimport re
324483Sgblack@eecs.umich.eduimport string
334483Sgblack@eecs.umich.eduimport traceback
344483Sgblack@eecs.umich.edu# get type names
354483Sgblack@eecs.umich.edufrom types import *
364483Sgblack@eecs.umich.edu
374483Sgblack@eecs.umich.edu# Prepend the directory where the PLY lex & yacc modules are found
384483Sgblack@eecs.umich.edu# to the search path.
394483Sgblack@eecs.umich.edusys.path[0:0] = [os.environ['M5_PLY']]
404483Sgblack@eecs.umich.edu
414483Sgblack@eecs.umich.edufrom ply import lex
424483Sgblack@eecs.umich.edufrom ply import yacc
434483Sgblack@eecs.umich.edu
444483Sgblack@eecs.umich.edu##########################################################################
454483Sgblack@eecs.umich.edu#
464483Sgblack@eecs.umich.edu# Base classes for use outside of the assembler
474483Sgblack@eecs.umich.edu#
484483Sgblack@eecs.umich.edu##########################################################################
494483Sgblack@eecs.umich.edu
504483Sgblack@eecs.umich.educlass Micro_Container(object):
514483Sgblack@eecs.umich.edu    def __init__(self, name):
524483Sgblack@eecs.umich.edu        self.microops = []
534483Sgblack@eecs.umich.edu        self.name = name
544483Sgblack@eecs.umich.edu        self.directives = {}
554483Sgblack@eecs.umich.edu        self.micro_classes = {}
564483Sgblack@eecs.umich.edu        self.labels = {}
574483Sgblack@eecs.umich.edu
584483Sgblack@eecs.umich.edu    def add_microop(self, microop):
594483Sgblack@eecs.umich.edu        self.microops.append(microop)
604483Sgblack@eecs.umich.edu
614483Sgblack@eecs.umich.edu    def __str__(self):
624483Sgblack@eecs.umich.edu        string = "%s:\n" % self.name
634483Sgblack@eecs.umich.edu        for microop in self.microops:
644483Sgblack@eecs.umich.edu            string += "  %s\n" % microop
654483Sgblack@eecs.umich.edu        return string
664483Sgblack@eecs.umich.edu
674507Sgblack@eecs.umich.educlass Combinational_Macroop(Micro_Container):
684483Sgblack@eecs.umich.edu    pass
694483Sgblack@eecs.umich.edu
704507Sgblack@eecs.umich.educlass Rom_Macroop(object):
714507Sgblack@eecs.umich.edu    def __init__(self, name, target):
724507Sgblack@eecs.umich.edu        self.name = name
734507Sgblack@eecs.umich.edu        self.target = target
744507Sgblack@eecs.umich.edu
754508Sgblack@eecs.umich.edu    def __str__(self):
764508Sgblack@eecs.umich.edu        return "%s: %s\n" % (self.name, self.target)
774508Sgblack@eecs.umich.edu
784483Sgblack@eecs.umich.educlass Rom(Micro_Container):
794483Sgblack@eecs.umich.edu    def __init__(self, name):
804483Sgblack@eecs.umich.edu        super(Rom, self).__init__(name)
814483Sgblack@eecs.umich.edu        self.externs = {}
824483Sgblack@eecs.umich.edu
834483Sgblack@eecs.umich.edu##########################################################################
844483Sgblack@eecs.umich.edu#
854483Sgblack@eecs.umich.edu# Support classes
864483Sgblack@eecs.umich.edu#
874483Sgblack@eecs.umich.edu##########################################################################
884483Sgblack@eecs.umich.edu
894483Sgblack@eecs.umich.educlass Label(object):
904483Sgblack@eecs.umich.edu    def __init__(self):
914483Sgblack@eecs.umich.edu        self.extern = False
924483Sgblack@eecs.umich.edu        self.name = ""
934483Sgblack@eecs.umich.edu
944483Sgblack@eecs.umich.educlass Block(object):
954483Sgblack@eecs.umich.edu    def __init__(self):
964483Sgblack@eecs.umich.edu        self.statements = []
974483Sgblack@eecs.umich.edu
984483Sgblack@eecs.umich.educlass Statement(object):
994483Sgblack@eecs.umich.edu    def __init__(self):
1004483Sgblack@eecs.umich.edu        self.is_microop = False
1014483Sgblack@eecs.umich.edu        self.is_directive = False
1024503Sgblack@eecs.umich.edu        self.params = ""
1034483Sgblack@eecs.umich.edu
1044483Sgblack@eecs.umich.educlass Microop(Statement):
1054483Sgblack@eecs.umich.edu    def __init__(self):
1064483Sgblack@eecs.umich.edu        super(Microop, self).__init__()
1074483Sgblack@eecs.umich.edu        self.mnemonic = ""
1084483Sgblack@eecs.umich.edu        self.labels = []
1094483Sgblack@eecs.umich.edu        self.is_microop = True
1104483Sgblack@eecs.umich.edu
1114483Sgblack@eecs.umich.educlass Directive(Statement):
1124483Sgblack@eecs.umich.edu    def __init__(self):
1134483Sgblack@eecs.umich.edu        super(Directive, self).__init__()
1144483Sgblack@eecs.umich.edu        self.name = ""
1154483Sgblack@eecs.umich.edu        self.is_directive = True
1164483Sgblack@eecs.umich.edu
1174483Sgblack@eecs.umich.edu##########################################################################
1184483Sgblack@eecs.umich.edu#
1194483Sgblack@eecs.umich.edu# Functions that handle common tasks
1204483Sgblack@eecs.umich.edu#
1214483Sgblack@eecs.umich.edu##########################################################################
1224483Sgblack@eecs.umich.edu
1234483Sgblack@eecs.umich.edudef print_error(message):
1244483Sgblack@eecs.umich.edu    print
1254483Sgblack@eecs.umich.edu    print "*** %s" % message
1264483Sgblack@eecs.umich.edu    print
1274483Sgblack@eecs.umich.edu
1284483Sgblack@eecs.umich.edudef handle_statement(parser, container, statement):
1294483Sgblack@eecs.umich.edu    if statement.is_microop:
1304613Sgblack@eecs.umich.edu        if statement.mnemonic not in parser.microops.keys():
1314613Sgblack@eecs.umich.edu            raise Exception, "Unrecognized mnemonic: %s" % statement.mnemonic
1324613Sgblack@eecs.umich.edu        parser.symbols["__microopClassFromInsideTheAssembler"] = \
1334613Sgblack@eecs.umich.edu            parser.microops[statement.mnemonic]
1344483Sgblack@eecs.umich.edu        try:
1354613Sgblack@eecs.umich.edu            microop = eval('__microopClassFromInsideTheAssembler(%s)' %
1364613Sgblack@eecs.umich.edu                    statement.params, {}, parser.symbols)
1374483Sgblack@eecs.umich.edu        except:
1384591Sgblack@eecs.umich.edu            print_error("Error creating microop object with mnemonic %s." % \
1394591Sgblack@eecs.umich.edu                    statement.mnemonic)
1404483Sgblack@eecs.umich.edu            raise
1414483Sgblack@eecs.umich.edu        try:
1424483Sgblack@eecs.umich.edu            for label in statement.labels:
1435009Sgblack@eecs.umich.edu                container.labels[label.text] = microop
1444483Sgblack@eecs.umich.edu                if label.extern:
1455009Sgblack@eecs.umich.edu                    container.externs[label.text] = microop
1464483Sgblack@eecs.umich.edu            container.add_microop(microop)
1474483Sgblack@eecs.umich.edu        except:
1484483Sgblack@eecs.umich.edu            print_error("Error adding microop.")
1494483Sgblack@eecs.umich.edu            raise
1504483Sgblack@eecs.umich.edu    elif statement.is_directive:
1514613Sgblack@eecs.umich.edu        if statement.name not in container.directives.keys():
1524613Sgblack@eecs.umich.edu            raise Exception, "Unrecognized directive: %s" % statement.name
1534613Sgblack@eecs.umich.edu        parser.symbols["__directiveFunctionFromInsideTheAssembler"] = \
1544613Sgblack@eecs.umich.edu            container.directives[statement.name]
1554483Sgblack@eecs.umich.edu        try:
1564613Sgblack@eecs.umich.edu            eval('__directiveFunctionFromInsideTheAssembler(%s)' %
1574613Sgblack@eecs.umich.edu                    statement.params, {}, parser.symbols)
1584483Sgblack@eecs.umich.edu        except:
1594483Sgblack@eecs.umich.edu            print_error("Error executing directive.")
1604483Sgblack@eecs.umich.edu            print container.directives
1614483Sgblack@eecs.umich.edu            raise
1624483Sgblack@eecs.umich.edu    else:
1634483Sgblack@eecs.umich.edu        raise Exception, "Didn't recognize the type of statement", statement
1644483Sgblack@eecs.umich.edu
1654483Sgblack@eecs.umich.edu##########################################################################
1664483Sgblack@eecs.umich.edu#
1674483Sgblack@eecs.umich.edu# Lexer specification
1684483Sgblack@eecs.umich.edu#
1694483Sgblack@eecs.umich.edu##########################################################################
1704483Sgblack@eecs.umich.edu
1714483Sgblack@eecs.umich.edu# Error handler.  Just call exit.  Output formatted to work under
1724483Sgblack@eecs.umich.edu# Emacs compile-mode.  Optional 'print_traceback' arg, if set to True,
1734483Sgblack@eecs.umich.edu# prints a Python stack backtrace too (can be handy when trying to
1744483Sgblack@eecs.umich.edu# debug the parser itself).
1754483Sgblack@eecs.umich.edudef error(lineno, string, print_traceback = False):
1764483Sgblack@eecs.umich.edu    # Print a Python stack backtrace if requested.
1774483Sgblack@eecs.umich.edu    if (print_traceback):
1784483Sgblack@eecs.umich.edu        traceback.print_exc()
1794483Sgblack@eecs.umich.edu    if lineno != 0:
1804483Sgblack@eecs.umich.edu        line_str = "%d:" % lineno
1814483Sgblack@eecs.umich.edu    else:
1824483Sgblack@eecs.umich.edu        line_str = ""
1834483Sgblack@eecs.umich.edu    sys.exit("%s %s" % (line_str, string))
1844483Sgblack@eecs.umich.edu
1854483Sgblack@eecs.umich.edureserved = ('DEF', 'MACROOP', 'ROM', 'EXTERN')
1864483Sgblack@eecs.umich.edu
1874483Sgblack@eecs.umich.edutokens = reserved + (
1884483Sgblack@eecs.umich.edu        # identifier
1894483Sgblack@eecs.umich.edu        'ID',
1904483Sgblack@eecs.umich.edu        # arguments for microops and directives
1914483Sgblack@eecs.umich.edu        'PARAMS',
1924483Sgblack@eecs.umich.edu
1934483Sgblack@eecs.umich.edu        'LPAREN', 'RPAREN',
1944483Sgblack@eecs.umich.edu        'LBRACE', 'RBRACE',
1954483Sgblack@eecs.umich.edu        'COLON', 'SEMI', 'DOT',
1964483Sgblack@eecs.umich.edu        'NEWLINE'
1974483Sgblack@eecs.umich.edu        )
1984483Sgblack@eecs.umich.edu
1994483Sgblack@eecs.umich.edu# New lines are ignored at the top level, but they end statements in the
2004483Sgblack@eecs.umich.edu# assembler
2014483Sgblack@eecs.umich.edustates = (
2024483Sgblack@eecs.umich.edu    ('asm', 'exclusive'),
2034483Sgblack@eecs.umich.edu    ('params', 'exclusive'),
2044483Sgblack@eecs.umich.edu)
2054483Sgblack@eecs.umich.edu
2064483Sgblack@eecs.umich.edureserved_map = { }
2074483Sgblack@eecs.umich.edufor r in reserved:
2084483Sgblack@eecs.umich.edu    reserved_map[r.lower()] = r
2094483Sgblack@eecs.umich.edu
2104512Sgblack@eecs.umich.edu# Ignore comments
2114502Sgblack@eecs.umich.edudef t_ANY_COMMENT(t):
2124502Sgblack@eecs.umich.edu    r'\#[^\n]*(?=\n)'
2134502Sgblack@eecs.umich.edu
2144502Sgblack@eecs.umich.edudef t_ANY_MULTILINECOMMENT(t):
2154502Sgblack@eecs.umich.edu    r'/\*([^/]|((?<!\*)/))*\*/'
2164502Sgblack@eecs.umich.edu
2174512Sgblack@eecs.umich.edu# A colon marks the end of a label. It should follow an ID which will
2184512Sgblack@eecs.umich.edu# put the lexer in the "params" state. Seeing the colon will put it back
2194512Sgblack@eecs.umich.edu# in the "asm" state since it knows it saw a label and not a mnemonic.
2204483Sgblack@eecs.umich.edudef t_params_COLON(t):
2214483Sgblack@eecs.umich.edu    r':'
2224483Sgblack@eecs.umich.edu    t.lexer.begin('asm')
2234483Sgblack@eecs.umich.edu    return t
2244483Sgblack@eecs.umich.edu
2254512Sgblack@eecs.umich.edu# Parameters are a string of text which don't contain an unescaped statement
2264512Sgblack@eecs.umich.edu# statement terminator, ie a newline or semi colon.
2274483Sgblack@eecs.umich.edudef t_params_PARAMS(t):
2284566Sgblack@eecs.umich.edu    r'([^\n;\\]|(\\[\n;\\]))+'
2294483Sgblack@eecs.umich.edu    t.lineno += t.value.count('\n')
2304566Sgblack@eecs.umich.edu    unescapeParamsRE = re.compile(r'(\\[\n;\\])')
2314566Sgblack@eecs.umich.edu    def unescapeParams(mo):
2324566Sgblack@eecs.umich.edu        val = mo.group(0)
2334566Sgblack@eecs.umich.edu        return val[1]
2344566Sgblack@eecs.umich.edu    t.value = unescapeParamsRE.sub(unescapeParams, t.value)
2354483Sgblack@eecs.umich.edu    t.lexer.begin('asm')
2364483Sgblack@eecs.umich.edu    return t
2374483Sgblack@eecs.umich.edu
2384613Sgblack@eecs.umich.edu# An "ID" in the micro assembler is either a label, directive, or mnemonic
2394613Sgblack@eecs.umich.edu# If it's either a directive or a mnemonic, it will be optionally followed by
2404613Sgblack@eecs.umich.edu# parameters. If it's a label, the following colon will make the lexer stop
2414613Sgblack@eecs.umich.edu# looking for parameters.
2424613Sgblack@eecs.umich.edudef t_asm_ID(t):
2434613Sgblack@eecs.umich.edu    r'[A-Za-z_]\w*'
2444613Sgblack@eecs.umich.edu    t.type = reserved_map.get(t.value, 'ID')
2454613Sgblack@eecs.umich.edu    t.lexer.begin('params')
2464613Sgblack@eecs.umich.edu    return t
2474613Sgblack@eecs.umich.edu
2484613Sgblack@eecs.umich.edu# If there is a label and you're -not- in the assembler (which would be caught
2494613Sgblack@eecs.umich.edu# above), don't start looking for parameters.
2504613Sgblack@eecs.umich.edudef t_ANY_ID(t):
2514613Sgblack@eecs.umich.edu    r'[A-Za-z_]\w*'
2524613Sgblack@eecs.umich.edu    t.type = reserved_map.get(t.value, 'ID')
2534613Sgblack@eecs.umich.edu    return t
2544613Sgblack@eecs.umich.edu
2554512Sgblack@eecs.umich.edu# Braces enter and exit micro assembly
2564483Sgblack@eecs.umich.edudef t_INITIAL_LBRACE(t):
2574483Sgblack@eecs.umich.edu    r'\{'
2584483Sgblack@eecs.umich.edu    t.lexer.begin('asm')
2594483Sgblack@eecs.umich.edu    return t
2604483Sgblack@eecs.umich.edu
2614483Sgblack@eecs.umich.edudef t_asm_RBRACE(t):
2624483Sgblack@eecs.umich.edu    r'\}'
2634483Sgblack@eecs.umich.edu    t.lexer.begin('INITIAL')
2644483Sgblack@eecs.umich.edu    return t
2654483Sgblack@eecs.umich.edu
2664512Sgblack@eecs.umich.edu# At the top level, keep track of newlines only for line counting.
2674483Sgblack@eecs.umich.edudef t_INITIAL_NEWLINE(t):
2684483Sgblack@eecs.umich.edu    r'\n+'
2694483Sgblack@eecs.umich.edu    t.lineno += t.value.count('\n')
2704483Sgblack@eecs.umich.edu
2714512Sgblack@eecs.umich.edu# In the micro assembler, do line counting but also return a token. The
2724512Sgblack@eecs.umich.edu# token is needed by the parser to detect the end of a statement.
2734483Sgblack@eecs.umich.edudef t_asm_NEWLINE(t):
2744483Sgblack@eecs.umich.edu    r'\n+'
2754483Sgblack@eecs.umich.edu    t.lineno += t.value.count('\n')
2764483Sgblack@eecs.umich.edu    return t
2774483Sgblack@eecs.umich.edu
2784512Sgblack@eecs.umich.edu# A newline or semi colon when looking for params signals that the statement
2794512Sgblack@eecs.umich.edu# is over and the lexer should go back to looking for regular assembly.
2804483Sgblack@eecs.umich.edudef t_params_NEWLINE(t):
2814483Sgblack@eecs.umich.edu    r'\n+'
2824483Sgblack@eecs.umich.edu    t.lineno += t.value.count('\n')
2834483Sgblack@eecs.umich.edu    t.lexer.begin('asm')
2844483Sgblack@eecs.umich.edu    return t
2854483Sgblack@eecs.umich.edu
2864483Sgblack@eecs.umich.edudef t_params_SEMI(t):
2874483Sgblack@eecs.umich.edu    r';'
2884483Sgblack@eecs.umich.edu    t.lexer.begin('asm')
2894483Sgblack@eecs.umich.edu    return t
2904483Sgblack@eecs.umich.edu
2914483Sgblack@eecs.umich.edu# Basic regular expressions to pick out simple tokens
2924483Sgblack@eecs.umich.edut_ANY_LPAREN = r'\('
2934483Sgblack@eecs.umich.edut_ANY_RPAREN = r'\)'
2944483Sgblack@eecs.umich.edut_ANY_SEMI   = r';'
2954483Sgblack@eecs.umich.edut_ANY_DOT    = r'\.'
2964483Sgblack@eecs.umich.edu
2974483Sgblack@eecs.umich.edut_ANY_ignore = ' \t\x0c'
2984483Sgblack@eecs.umich.edu
2994483Sgblack@eecs.umich.edudef t_ANY_error(t):
3004483Sgblack@eecs.umich.edu    error(t.lineno, "illegal character '%s'" % t.value[0])
3014483Sgblack@eecs.umich.edu    t.skip(1)
3024483Sgblack@eecs.umich.edu
3034483Sgblack@eecs.umich.edu##########################################################################
3044483Sgblack@eecs.umich.edu#
3054483Sgblack@eecs.umich.edu# Parser specification
3064483Sgblack@eecs.umich.edu#
3074483Sgblack@eecs.umich.edu##########################################################################
3084483Sgblack@eecs.umich.edu
3094483Sgblack@eecs.umich.edu# Start symbol for a file which may have more than one macroop or rom
3104483Sgblack@eecs.umich.edu# specification.
3114483Sgblack@eecs.umich.edudef p_file(t):
3124483Sgblack@eecs.umich.edu    'file : opt_rom_or_macros'
3134483Sgblack@eecs.umich.edu
3144483Sgblack@eecs.umich.edudef p_opt_rom_or_macros_0(t):
3154483Sgblack@eecs.umich.edu    'opt_rom_or_macros : '
3164483Sgblack@eecs.umich.edu
3174483Sgblack@eecs.umich.edudef p_opt_rom_or_macros_1(t):
3184483Sgblack@eecs.umich.edu    'opt_rom_or_macros : rom_or_macros'
3194483Sgblack@eecs.umich.edu
3204483Sgblack@eecs.umich.edudef p_rom_or_macros_0(t):
3214483Sgblack@eecs.umich.edu    'rom_or_macros : rom_or_macro'
3224483Sgblack@eecs.umich.edu
3234483Sgblack@eecs.umich.edudef p_rom_or_macros_1(t):
3244483Sgblack@eecs.umich.edu    'rom_or_macros : rom_or_macros rom_or_macro'
3254483Sgblack@eecs.umich.edu
3264483Sgblack@eecs.umich.edudef p_rom_or_macro_0(t):
3274512Sgblack@eecs.umich.edu    '''rom_or_macro : rom_block
3284512Sgblack@eecs.umich.edu                    | macroop_def'''
3294483Sgblack@eecs.umich.edu
3304483Sgblack@eecs.umich.edu# Defines a section of microcode that should go in the current ROM
3314483Sgblack@eecs.umich.edudef p_rom_block(t):
3324483Sgblack@eecs.umich.edu    'rom_block : DEF ROM block SEMI'
3334507Sgblack@eecs.umich.edu    if not t.parser.rom:
3344507Sgblack@eecs.umich.edu        print_error("Rom block found, but no Rom object specified.")
3354507Sgblack@eecs.umich.edu        raise TypeError, "Rom block found, but no Rom object was specified."
3364483Sgblack@eecs.umich.edu    for statement in t[3].statements:
3374483Sgblack@eecs.umich.edu        handle_statement(t.parser, t.parser.rom, statement)
3384483Sgblack@eecs.umich.edu    t[0] = t.parser.rom
3394483Sgblack@eecs.umich.edu
3404483Sgblack@eecs.umich.edu# Defines a macroop that jumps to an external label in the ROM
3414483Sgblack@eecs.umich.edudef p_macroop_def_0(t):
3424502Sgblack@eecs.umich.edu    'macroop_def : DEF MACROOP ID LPAREN ID RPAREN SEMI'
3434507Sgblack@eecs.umich.edu    if not t.parser.rom_macroop_type:
3444507Sgblack@eecs.umich.edu        print_error("ROM based macroop found, but no ROM macroop class was specified.")
3454507Sgblack@eecs.umich.edu        raise TypeError, "ROM based macroop found, but no ROM macroop class was specified."
3464507Sgblack@eecs.umich.edu    macroop = t.parser.rom_macroop_type(t[3], t[5])
3474508Sgblack@eecs.umich.edu    t.parser.macroops[t[3]] = macroop
3484507Sgblack@eecs.umich.edu
3494483Sgblack@eecs.umich.edu
3504483Sgblack@eecs.umich.edu# Defines a macroop that is combinationally generated
3514483Sgblack@eecs.umich.edudef p_macroop_def_1(t):
3524483Sgblack@eecs.umich.edu    'macroop_def : DEF MACROOP ID block SEMI'
3534483Sgblack@eecs.umich.edu    try:
3544483Sgblack@eecs.umich.edu        curop = t.parser.macro_type(t[3])
3554483Sgblack@eecs.umich.edu    except TypeError:
3564483Sgblack@eecs.umich.edu        print_error("Error creating macroop object.")
3574483Sgblack@eecs.umich.edu        raise
3584483Sgblack@eecs.umich.edu    for statement in t[4].statements:
3594483Sgblack@eecs.umich.edu        handle_statement(t.parser, curop, statement)
3604502Sgblack@eecs.umich.edu    t.parser.macroops[t[3]] = curop
3614483Sgblack@eecs.umich.edu
3624512Sgblack@eecs.umich.edu# A block of statements
3634512Sgblack@eecs.umich.edudef p_block(t):
3644512Sgblack@eecs.umich.edu    'block : LBRACE statements RBRACE'
3654512Sgblack@eecs.umich.edu    block = Block()
3664512Sgblack@eecs.umich.edu    block.statements = t[2]
3674512Sgblack@eecs.umich.edu    t[0] = block
3684512Sgblack@eecs.umich.edu
3694483Sgblack@eecs.umich.edudef p_statements_0(t):
3704483Sgblack@eecs.umich.edu    'statements : statement'
3714483Sgblack@eecs.umich.edu    if t[1]:
3724483Sgblack@eecs.umich.edu        t[0] = [t[1]]
3734483Sgblack@eecs.umich.edu    else:
3744483Sgblack@eecs.umich.edu        t[0] = []
3754483Sgblack@eecs.umich.edu
3764483Sgblack@eecs.umich.edudef p_statements_1(t):
3774483Sgblack@eecs.umich.edu    'statements : statements statement'
3784483Sgblack@eecs.umich.edu    if t[2]:
3794483Sgblack@eecs.umich.edu        t[1].append(t[2])
3804483Sgblack@eecs.umich.edu    t[0] = t[1]
3814483Sgblack@eecs.umich.edu
3824483Sgblack@eecs.umich.edudef p_statement(t):
3834483Sgblack@eecs.umich.edu    'statement : content_of_statement end_of_statement'
3844483Sgblack@eecs.umich.edu    t[0] = t[1]
3854483Sgblack@eecs.umich.edu
3864483Sgblack@eecs.umich.edu# A statement can be a microop or an assembler directive
3874483Sgblack@eecs.umich.edudef p_content_of_statement_0(t):
3884483Sgblack@eecs.umich.edu    '''content_of_statement : microop
3894483Sgblack@eecs.umich.edu                            | directive'''
3904483Sgblack@eecs.umich.edu    t[0] = t[1]
3914483Sgblack@eecs.umich.edu
3924512Sgblack@eecs.umich.edu# Ignore empty statements
3934483Sgblack@eecs.umich.edudef p_content_of_statement_1(t):
3944483Sgblack@eecs.umich.edu    'content_of_statement : '
3954483Sgblack@eecs.umich.edu    pass
3964483Sgblack@eecs.umich.edu
3974483Sgblack@eecs.umich.edu# Statements are ended by newlines or a semi colon
3984483Sgblack@eecs.umich.edudef p_end_of_statement(t):
3994483Sgblack@eecs.umich.edu    '''end_of_statement : NEWLINE
4004483Sgblack@eecs.umich.edu                        | SEMI'''
4014483Sgblack@eecs.umich.edu    pass
4024483Sgblack@eecs.umich.edu
4034512Sgblack@eecs.umich.edu# Different flavors of microop to avoid shift/reduce errors
4044483Sgblack@eecs.umich.edudef p_microop_0(t):
4054483Sgblack@eecs.umich.edu    'microop : labels ID'
4064483Sgblack@eecs.umich.edu    microop = Microop()
4074483Sgblack@eecs.umich.edu    microop.labels = t[1]
4084483Sgblack@eecs.umich.edu    microop.mnemonic = t[2]
4094483Sgblack@eecs.umich.edu    t[0] = microop
4104483Sgblack@eecs.umich.edu
4114483Sgblack@eecs.umich.edudef p_microop_1(t):
4124483Sgblack@eecs.umich.edu    'microop : ID'
4134483Sgblack@eecs.umich.edu    microop = Microop()
4144483Sgblack@eecs.umich.edu    microop.mnemonic = t[1]
4154483Sgblack@eecs.umich.edu    t[0] = microop
4164483Sgblack@eecs.umich.edu
4174483Sgblack@eecs.umich.edudef p_microop_2(t):
4184483Sgblack@eecs.umich.edu    'microop : labels ID PARAMS'
4194483Sgblack@eecs.umich.edu    microop = Microop()
4204483Sgblack@eecs.umich.edu    microop.labels = t[1]
4214483Sgblack@eecs.umich.edu    microop.mnemonic = t[2]
4224483Sgblack@eecs.umich.edu    microop.params = t[3]
4234483Sgblack@eecs.umich.edu    t[0] = microop
4244483Sgblack@eecs.umich.edu
4254483Sgblack@eecs.umich.edudef p_microop_3(t):
4264483Sgblack@eecs.umich.edu    'microop : ID PARAMS'
4274483Sgblack@eecs.umich.edu    microop = Microop()
4284483Sgblack@eecs.umich.edu    microop.mnemonic = t[1]
4294483Sgblack@eecs.umich.edu    microop.params = t[2]
4304483Sgblack@eecs.umich.edu    t[0] = microop
4314483Sgblack@eecs.umich.edu
4324512Sgblack@eecs.umich.edu# Labels in the microcode
4334483Sgblack@eecs.umich.edudef p_labels_0(t):
4344483Sgblack@eecs.umich.edu    'labels : label'
4354483Sgblack@eecs.umich.edu    t[0] = [t[1]]
4364483Sgblack@eecs.umich.edu
4374483Sgblack@eecs.umich.edudef p_labels_1(t):
4384483Sgblack@eecs.umich.edu    'labels : labels label'
4394483Sgblack@eecs.umich.edu    t[1].append(t[2])
4404483Sgblack@eecs.umich.edu    t[0] = t[1]
4414483Sgblack@eecs.umich.edu
4425009Sgblack@eecs.umich.edu# labels on lines by themselves are attached to the following instruction.
4435009Sgblack@eecs.umich.edudef p_labels_2(t):
4445009Sgblack@eecs.umich.edu    'labels : labels NEWLINE'
4455009Sgblack@eecs.umich.edu    t[0] = t[1]
4465009Sgblack@eecs.umich.edu
4474483Sgblack@eecs.umich.edudef p_label_0(t):
4484483Sgblack@eecs.umich.edu    'label : ID COLON'
4494483Sgblack@eecs.umich.edu    label = Label()
4504483Sgblack@eecs.umich.edu    label.is_extern = False
4514483Sgblack@eecs.umich.edu    label.text = t[1]
4524483Sgblack@eecs.umich.edu    t[0] = label
4534483Sgblack@eecs.umich.edu
4544483Sgblack@eecs.umich.edudef p_label_1(t):
4554483Sgblack@eecs.umich.edu    'label : EXTERN ID COLON'
4564483Sgblack@eecs.umich.edu    label = Label()
4574483Sgblack@eecs.umich.edu    label.is_extern = True
4584483Sgblack@eecs.umich.edu    label.text = t[2]
4594483Sgblack@eecs.umich.edu    t[0] = label
4604483Sgblack@eecs.umich.edu
4614512Sgblack@eecs.umich.edu# Directives for the macroop
4624503Sgblack@eecs.umich.edudef p_directive_0(t):
4634483Sgblack@eecs.umich.edu    'directive : DOT ID'
4644483Sgblack@eecs.umich.edu    directive = Directive()
4654483Sgblack@eecs.umich.edu    directive.name = t[2]
4664483Sgblack@eecs.umich.edu    t[0] = directive
4674483Sgblack@eecs.umich.edu
4684503Sgblack@eecs.umich.edudef p_directive_1(t):
4694503Sgblack@eecs.umich.edu    'directive : DOT ID PARAMS'
4704503Sgblack@eecs.umich.edu    directive = Directive()
4714503Sgblack@eecs.umich.edu    directive.name = t[2]
4724503Sgblack@eecs.umich.edu    directive.params = t[3]
4734503Sgblack@eecs.umich.edu    t[0] = directive
4744503Sgblack@eecs.umich.edu
4754483Sgblack@eecs.umich.edu# Parse error handler.  Note that the argument here is the offending
4764483Sgblack@eecs.umich.edu# *token*, not a grammar symbol (hence the need to use t.value)
4774483Sgblack@eecs.umich.edudef p_error(t):
4784483Sgblack@eecs.umich.edu    if t:
4794483Sgblack@eecs.umich.edu        error(t.lineno, "syntax error at '%s'" % t.value)
4804483Sgblack@eecs.umich.edu    else:
4814483Sgblack@eecs.umich.edu        error(0, "unknown syntax error", True)
4824483Sgblack@eecs.umich.edu
4834483Sgblack@eecs.umich.educlass MicroAssembler(object):
4844483Sgblack@eecs.umich.edu
4854507Sgblack@eecs.umich.edu    def __init__(self, macro_type, microops,
4864507Sgblack@eecs.umich.edu            rom = None, rom_macroop_type = None):
4874483Sgblack@eecs.umich.edu        self.lexer = lex.lex()
4884483Sgblack@eecs.umich.edu        self.parser = yacc.yacc()
4894483Sgblack@eecs.umich.edu        self.parser.macro_type = macro_type
4904502Sgblack@eecs.umich.edu        self.parser.macroops = {}
4914483Sgblack@eecs.umich.edu        self.parser.microops = microops
4924483Sgblack@eecs.umich.edu        self.parser.rom = rom
4934507Sgblack@eecs.umich.edu        self.parser.rom_macroop_type = rom_macroop_type
4944613Sgblack@eecs.umich.edu        self.parser.symbols = {}
4954613Sgblack@eecs.umich.edu        self.symbols = self.parser.symbols
4964483Sgblack@eecs.umich.edu
4974483Sgblack@eecs.umich.edu    def assemble(self, asm):
4984483Sgblack@eecs.umich.edu        self.parser.parse(asm, lexer=self.lexer)
4994483Sgblack@eecs.umich.edu        macroops = self.parser.macroops
5004502Sgblack@eecs.umich.edu        self.parser.macroops = {}
5014483Sgblack@eecs.umich.edu        return macroops
502