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
2912563Sgabeblack@google.comfrom __future__ import print_function
3012563Sgabeblack@google.com
314483Sgblack@eecs.umich.eduimport os
324483Sgblack@eecs.umich.eduimport sys
334483Sgblack@eecs.umich.eduimport re
344483Sgblack@eecs.umich.eduimport string
354483Sgblack@eecs.umich.eduimport traceback
364483Sgblack@eecs.umich.edu# get type names
374483Sgblack@eecs.umich.edufrom types import *
384483Sgblack@eecs.umich.edu
394483Sgblack@eecs.umich.edufrom ply import lex
404483Sgblack@eecs.umich.edufrom ply import yacc
414483Sgblack@eecs.umich.edu
424483Sgblack@eecs.umich.edu##########################################################################
434483Sgblack@eecs.umich.edu#
444483Sgblack@eecs.umich.edu# Base classes for use outside of the assembler
454483Sgblack@eecs.umich.edu#
464483Sgblack@eecs.umich.edu##########################################################################
474483Sgblack@eecs.umich.edu
484483Sgblack@eecs.umich.educlass Micro_Container(object):
494483Sgblack@eecs.umich.edu    def __init__(self, name):
504483Sgblack@eecs.umich.edu        self.microops = []
514483Sgblack@eecs.umich.edu        self.name = name
524483Sgblack@eecs.umich.edu        self.directives = {}
534483Sgblack@eecs.umich.edu        self.micro_classes = {}
544483Sgblack@eecs.umich.edu        self.labels = {}
554483Sgblack@eecs.umich.edu
565039Sgblack@eecs.umich.edu    def add_microop(self, mnemonic, microop):
574483Sgblack@eecs.umich.edu        self.microops.append(microop)
584483Sgblack@eecs.umich.edu
594483Sgblack@eecs.umich.edu    def __str__(self):
604483Sgblack@eecs.umich.edu        string = "%s:\n" % self.name
614483Sgblack@eecs.umich.edu        for microop in self.microops:
624483Sgblack@eecs.umich.edu            string += "  %s\n" % microop
634483Sgblack@eecs.umich.edu        return string
644483Sgblack@eecs.umich.edu
654507Sgblack@eecs.umich.educlass Combinational_Macroop(Micro_Container):
664483Sgblack@eecs.umich.edu    pass
674483Sgblack@eecs.umich.edu
684507Sgblack@eecs.umich.educlass Rom_Macroop(object):
694507Sgblack@eecs.umich.edu    def __init__(self, name, target):
704507Sgblack@eecs.umich.edu        self.name = name
714507Sgblack@eecs.umich.edu        self.target = target
724507Sgblack@eecs.umich.edu
734508Sgblack@eecs.umich.edu    def __str__(self):
744508Sgblack@eecs.umich.edu        return "%s: %s\n" % (self.name, self.target)
754508Sgblack@eecs.umich.edu
764483Sgblack@eecs.umich.educlass Rom(Micro_Container):
774483Sgblack@eecs.umich.edu    def __init__(self, name):
784483Sgblack@eecs.umich.edu        super(Rom, self).__init__(name)
794483Sgblack@eecs.umich.edu        self.externs = {}
804483Sgblack@eecs.umich.edu
814483Sgblack@eecs.umich.edu##########################################################################
824483Sgblack@eecs.umich.edu#
834483Sgblack@eecs.umich.edu# Support classes
844483Sgblack@eecs.umich.edu#
854483Sgblack@eecs.umich.edu##########################################################################
864483Sgblack@eecs.umich.edu
874483Sgblack@eecs.umich.educlass Label(object):
884483Sgblack@eecs.umich.edu    def __init__(self):
894483Sgblack@eecs.umich.edu        self.extern = False
904483Sgblack@eecs.umich.edu        self.name = ""
914483Sgblack@eecs.umich.edu
924483Sgblack@eecs.umich.educlass Block(object):
934483Sgblack@eecs.umich.edu    def __init__(self):
944483Sgblack@eecs.umich.edu        self.statements = []
954483Sgblack@eecs.umich.edu
964483Sgblack@eecs.umich.educlass Statement(object):
974483Sgblack@eecs.umich.edu    def __init__(self):
984483Sgblack@eecs.umich.edu        self.is_microop = False
994483Sgblack@eecs.umich.edu        self.is_directive = False
1004503Sgblack@eecs.umich.edu        self.params = ""
1014483Sgblack@eecs.umich.edu
1024483Sgblack@eecs.umich.educlass Microop(Statement):
1034483Sgblack@eecs.umich.edu    def __init__(self):
1044483Sgblack@eecs.umich.edu        super(Microop, self).__init__()
1054483Sgblack@eecs.umich.edu        self.mnemonic = ""
1064483Sgblack@eecs.umich.edu        self.labels = []
1074483Sgblack@eecs.umich.edu        self.is_microop = True
1084483Sgblack@eecs.umich.edu
1094483Sgblack@eecs.umich.educlass Directive(Statement):
1104483Sgblack@eecs.umich.edu    def __init__(self):
1114483Sgblack@eecs.umich.edu        super(Directive, self).__init__()
1124483Sgblack@eecs.umich.edu        self.name = ""
1134483Sgblack@eecs.umich.edu        self.is_directive = True
1144483Sgblack@eecs.umich.edu
1154483Sgblack@eecs.umich.edu##########################################################################
1164483Sgblack@eecs.umich.edu#
1174483Sgblack@eecs.umich.edu# Functions that handle common tasks
1184483Sgblack@eecs.umich.edu#
1194483Sgblack@eecs.umich.edu##########################################################################
1204483Sgblack@eecs.umich.edu
1214483Sgblack@eecs.umich.edudef print_error(message):
12212563Sgabeblack@google.com    print()
12312563Sgabeblack@google.com    print("*** %s" % message)
12412563Sgabeblack@google.com    print()
1254483Sgblack@eecs.umich.edu
1264483Sgblack@eecs.umich.edudef handle_statement(parser, container, statement):
1274483Sgblack@eecs.umich.edu    if statement.is_microop:
1284613Sgblack@eecs.umich.edu        if statement.mnemonic not in parser.microops.keys():
1294613Sgblack@eecs.umich.edu            raise Exception, "Unrecognized mnemonic: %s" % statement.mnemonic
1304613Sgblack@eecs.umich.edu        parser.symbols["__microopClassFromInsideTheAssembler"] = \
1314613Sgblack@eecs.umich.edu            parser.microops[statement.mnemonic]
1324483Sgblack@eecs.umich.edu        try:
1334613Sgblack@eecs.umich.edu            microop = eval('__microopClassFromInsideTheAssembler(%s)' %
1344613Sgblack@eecs.umich.edu                    statement.params, {}, parser.symbols)
1354483Sgblack@eecs.umich.edu        except:
1364591Sgblack@eecs.umich.edu            print_error("Error creating microop object with mnemonic %s." % \
1374591Sgblack@eecs.umich.edu                    statement.mnemonic)
1384483Sgblack@eecs.umich.edu            raise
1394483Sgblack@eecs.umich.edu        try:
1404483Sgblack@eecs.umich.edu            for label in statement.labels:
1415009Sgblack@eecs.umich.edu                container.labels[label.text] = microop
1425594Sgblack@eecs.umich.edu                if label.is_extern:
1435009Sgblack@eecs.umich.edu                    container.externs[label.text] = microop
1445039Sgblack@eecs.umich.edu            container.add_microop(statement.mnemonic, microop)
1454483Sgblack@eecs.umich.edu        except:
1464483Sgblack@eecs.umich.edu            print_error("Error adding microop.")
1474483Sgblack@eecs.umich.edu            raise
1484483Sgblack@eecs.umich.edu    elif statement.is_directive:
1494613Sgblack@eecs.umich.edu        if statement.name not in container.directives.keys():
1504613Sgblack@eecs.umich.edu            raise Exception, "Unrecognized directive: %s" % statement.name
1514613Sgblack@eecs.umich.edu        parser.symbols["__directiveFunctionFromInsideTheAssembler"] = \
1524613Sgblack@eecs.umich.edu            container.directives[statement.name]
1534483Sgblack@eecs.umich.edu        try:
1544613Sgblack@eecs.umich.edu            eval('__directiveFunctionFromInsideTheAssembler(%s)' %
1554613Sgblack@eecs.umich.edu                    statement.params, {}, parser.symbols)
1564483Sgblack@eecs.umich.edu        except:
1574483Sgblack@eecs.umich.edu            print_error("Error executing directive.")
15812563Sgabeblack@google.com            print(container.directives)
1594483Sgblack@eecs.umich.edu            raise
1604483Sgblack@eecs.umich.edu    else:
1614483Sgblack@eecs.umich.edu        raise Exception, "Didn't recognize the type of statement", statement
1624483Sgblack@eecs.umich.edu
1634483Sgblack@eecs.umich.edu##########################################################################
1644483Sgblack@eecs.umich.edu#
1654483Sgblack@eecs.umich.edu# Lexer specification
1664483Sgblack@eecs.umich.edu#
1674483Sgblack@eecs.umich.edu##########################################################################
1684483Sgblack@eecs.umich.edu
1694483Sgblack@eecs.umich.edu# Error handler.  Just call exit.  Output formatted to work under
1704483Sgblack@eecs.umich.edu# Emacs compile-mode.  Optional 'print_traceback' arg, if set to True,
1714483Sgblack@eecs.umich.edu# prints a Python stack backtrace too (can be handy when trying to
1724483Sgblack@eecs.umich.edu# debug the parser itself).
1734483Sgblack@eecs.umich.edudef error(lineno, string, print_traceback = False):
1744483Sgblack@eecs.umich.edu    # Print a Python stack backtrace if requested.
1754483Sgblack@eecs.umich.edu    if (print_traceback):
1764483Sgblack@eecs.umich.edu        traceback.print_exc()
1774483Sgblack@eecs.umich.edu    if lineno != 0:
1784483Sgblack@eecs.umich.edu        line_str = "%d:" % lineno
1794483Sgblack@eecs.umich.edu    else:
1804483Sgblack@eecs.umich.edu        line_str = ""
1814483Sgblack@eecs.umich.edu    sys.exit("%s %s" % (line_str, string))
1824483Sgblack@eecs.umich.edu
1834483Sgblack@eecs.umich.edureserved = ('DEF', 'MACROOP', 'ROM', 'EXTERN')
1844483Sgblack@eecs.umich.edu
1854483Sgblack@eecs.umich.edutokens = reserved + (
1864483Sgblack@eecs.umich.edu        # identifier
1874483Sgblack@eecs.umich.edu        'ID',
1884483Sgblack@eecs.umich.edu        # arguments for microops and directives
1894483Sgblack@eecs.umich.edu        'PARAMS',
1904483Sgblack@eecs.umich.edu
1914483Sgblack@eecs.umich.edu        'LPAREN', 'RPAREN',
1924483Sgblack@eecs.umich.edu        'LBRACE', 'RBRACE',
1934483Sgblack@eecs.umich.edu        'COLON', 'SEMI', 'DOT',
1944483Sgblack@eecs.umich.edu        'NEWLINE'
1954483Sgblack@eecs.umich.edu        )
1964483Sgblack@eecs.umich.edu
1974483Sgblack@eecs.umich.edu# New lines are ignored at the top level, but they end statements in the
1984483Sgblack@eecs.umich.edu# assembler
1994483Sgblack@eecs.umich.edustates = (
2004483Sgblack@eecs.umich.edu    ('asm', 'exclusive'),
2014483Sgblack@eecs.umich.edu    ('params', 'exclusive'),
2024483Sgblack@eecs.umich.edu)
2034483Sgblack@eecs.umich.edu
2044483Sgblack@eecs.umich.edureserved_map = { }
2054483Sgblack@eecs.umich.edufor r in reserved:
2064483Sgblack@eecs.umich.edu    reserved_map[r.lower()] = r
2074483Sgblack@eecs.umich.edu
2084512Sgblack@eecs.umich.edu# Ignore comments
2094502Sgblack@eecs.umich.edudef t_ANY_COMMENT(t):
2104502Sgblack@eecs.umich.edu    r'\#[^\n]*(?=\n)'
2114502Sgblack@eecs.umich.edu
2124502Sgblack@eecs.umich.edudef t_ANY_MULTILINECOMMENT(t):
2134502Sgblack@eecs.umich.edu    r'/\*([^/]|((?<!\*)/))*\*/'
2144502Sgblack@eecs.umich.edu
2154512Sgblack@eecs.umich.edu# A colon marks the end of a label. It should follow an ID which will
2164512Sgblack@eecs.umich.edu# put the lexer in the "params" state. Seeing the colon will put it back
2174512Sgblack@eecs.umich.edu# in the "asm" state since it knows it saw a label and not a mnemonic.
2184483Sgblack@eecs.umich.edudef t_params_COLON(t):
2194483Sgblack@eecs.umich.edu    r':'
2204483Sgblack@eecs.umich.edu    t.lexer.begin('asm')
2214483Sgblack@eecs.umich.edu    return t
2224483Sgblack@eecs.umich.edu
2234512Sgblack@eecs.umich.edu# Parameters are a string of text which don't contain an unescaped statement
2244512Sgblack@eecs.umich.edu# statement terminator, ie a newline or semi colon.
2254483Sgblack@eecs.umich.edudef t_params_PARAMS(t):
2264566Sgblack@eecs.umich.edu    r'([^\n;\\]|(\\[\n;\\]))+'
2274483Sgblack@eecs.umich.edu    t.lineno += t.value.count('\n')
2284566Sgblack@eecs.umich.edu    unescapeParamsRE = re.compile(r'(\\[\n;\\])')
2294566Sgblack@eecs.umich.edu    def unescapeParams(mo):
2304566Sgblack@eecs.umich.edu        val = mo.group(0)
2314566Sgblack@eecs.umich.edu        return val[1]
2324566Sgblack@eecs.umich.edu    t.value = unescapeParamsRE.sub(unescapeParams, t.value)
2334483Sgblack@eecs.umich.edu    t.lexer.begin('asm')
2344483Sgblack@eecs.umich.edu    return t
2354483Sgblack@eecs.umich.edu
2364613Sgblack@eecs.umich.edu# An "ID" in the micro assembler is either a label, directive, or mnemonic
2374613Sgblack@eecs.umich.edu# If it's either a directive or a mnemonic, it will be optionally followed by
2384613Sgblack@eecs.umich.edu# parameters. If it's a label, the following colon will make the lexer stop
2394613Sgblack@eecs.umich.edu# looking for parameters.
2404613Sgblack@eecs.umich.edudef t_asm_ID(t):
2414613Sgblack@eecs.umich.edu    r'[A-Za-z_]\w*'
2424613Sgblack@eecs.umich.edu    t.type = reserved_map.get(t.value, 'ID')
2435593Sgblack@eecs.umich.edu    # If the ID is really "extern", we shouldn't start looking for parameters
2445593Sgblack@eecs.umich.edu    # yet. The real ID, the label itself, is coming up.
2455593Sgblack@eecs.umich.edu    if t.type != 'EXTERN':
2465593Sgblack@eecs.umich.edu        t.lexer.begin('params')
2474613Sgblack@eecs.umich.edu    return t
2484613Sgblack@eecs.umich.edu
2494613Sgblack@eecs.umich.edu# If there is a label and you're -not- in the assembler (which would be caught
2504613Sgblack@eecs.umich.edu# above), don't start looking for parameters.
2514613Sgblack@eecs.umich.edudef t_ANY_ID(t):
2524613Sgblack@eecs.umich.edu    r'[A-Za-z_]\w*'
2534613Sgblack@eecs.umich.edu    t.type = reserved_map.get(t.value, 'ID')
2544613Sgblack@eecs.umich.edu    return t
2554613Sgblack@eecs.umich.edu
2564512Sgblack@eecs.umich.edu# Braces enter and exit micro assembly
2574483Sgblack@eecs.umich.edudef t_INITIAL_LBRACE(t):
2584483Sgblack@eecs.umich.edu    r'\{'
2594483Sgblack@eecs.umich.edu    t.lexer.begin('asm')
2604483Sgblack@eecs.umich.edu    return t
2614483Sgblack@eecs.umich.edu
2624483Sgblack@eecs.umich.edudef t_asm_RBRACE(t):
2634483Sgblack@eecs.umich.edu    r'\}'
2644483Sgblack@eecs.umich.edu    t.lexer.begin('INITIAL')
2654483Sgblack@eecs.umich.edu    return t
2664483Sgblack@eecs.umich.edu
2674512Sgblack@eecs.umich.edu# At the top level, keep track of newlines only for line counting.
2684483Sgblack@eecs.umich.edudef t_INITIAL_NEWLINE(t):
2694483Sgblack@eecs.umich.edu    r'\n+'
2704483Sgblack@eecs.umich.edu    t.lineno += t.value.count('\n')
2714483Sgblack@eecs.umich.edu
2724512Sgblack@eecs.umich.edu# In the micro assembler, do line counting but also return a token. The
2734512Sgblack@eecs.umich.edu# token is needed by the parser to detect the end of a statement.
2744483Sgblack@eecs.umich.edudef t_asm_NEWLINE(t):
2754483Sgblack@eecs.umich.edu    r'\n+'
2764483Sgblack@eecs.umich.edu    t.lineno += t.value.count('\n')
2774483Sgblack@eecs.umich.edu    return t
2784483Sgblack@eecs.umich.edu
2794512Sgblack@eecs.umich.edu# A newline or semi colon when looking for params signals that the statement
2804512Sgblack@eecs.umich.edu# is over and the lexer should go back to looking for regular assembly.
2814483Sgblack@eecs.umich.edudef t_params_NEWLINE(t):
2824483Sgblack@eecs.umich.edu    r'\n+'
2834483Sgblack@eecs.umich.edu    t.lineno += t.value.count('\n')
2844483Sgblack@eecs.umich.edu    t.lexer.begin('asm')
2854483Sgblack@eecs.umich.edu    return t
2864483Sgblack@eecs.umich.edu
2874483Sgblack@eecs.umich.edudef t_params_SEMI(t):
2884483Sgblack@eecs.umich.edu    r';'
2894483Sgblack@eecs.umich.edu    t.lexer.begin('asm')
2904483Sgblack@eecs.umich.edu    return t
2914483Sgblack@eecs.umich.edu
2924483Sgblack@eecs.umich.edu# Basic regular expressions to pick out simple tokens
2934483Sgblack@eecs.umich.edut_ANY_LPAREN = r'\('
2944483Sgblack@eecs.umich.edut_ANY_RPAREN = r'\)'
2954483Sgblack@eecs.umich.edut_ANY_SEMI   = r';'
2964483Sgblack@eecs.umich.edut_ANY_DOT    = r'\.'
2974483Sgblack@eecs.umich.edu
2984483Sgblack@eecs.umich.edut_ANY_ignore = ' \t\x0c'
2994483Sgblack@eecs.umich.edu
3004483Sgblack@eecs.umich.edudef t_ANY_error(t):
3014483Sgblack@eecs.umich.edu    error(t.lineno, "illegal character '%s'" % t.value[0])
3024483Sgblack@eecs.umich.edu    t.skip(1)
3034483Sgblack@eecs.umich.edu
3044483Sgblack@eecs.umich.edu##########################################################################
3054483Sgblack@eecs.umich.edu#
3064483Sgblack@eecs.umich.edu# Parser specification
3074483Sgblack@eecs.umich.edu#
3084483Sgblack@eecs.umich.edu##########################################################################
3094483Sgblack@eecs.umich.edu
3104483Sgblack@eecs.umich.edu# Start symbol for a file which may have more than one macroop or rom
3114483Sgblack@eecs.umich.edu# specification.
3124483Sgblack@eecs.umich.edudef p_file(t):
3134483Sgblack@eecs.umich.edu    'file : opt_rom_or_macros'
3144483Sgblack@eecs.umich.edu
3154483Sgblack@eecs.umich.edudef p_opt_rom_or_macros_0(t):
3164483Sgblack@eecs.umich.edu    'opt_rom_or_macros : '
3174483Sgblack@eecs.umich.edu
3184483Sgblack@eecs.umich.edudef p_opt_rom_or_macros_1(t):
3194483Sgblack@eecs.umich.edu    'opt_rom_or_macros : rom_or_macros'
3204483Sgblack@eecs.umich.edu
3214483Sgblack@eecs.umich.edudef p_rom_or_macros_0(t):
3224483Sgblack@eecs.umich.edu    'rom_or_macros : rom_or_macro'
3234483Sgblack@eecs.umich.edu
3244483Sgblack@eecs.umich.edudef p_rom_or_macros_1(t):
3254483Sgblack@eecs.umich.edu    'rom_or_macros : rom_or_macros rom_or_macro'
3264483Sgblack@eecs.umich.edu
3274483Sgblack@eecs.umich.edudef p_rom_or_macro_0(t):
3284512Sgblack@eecs.umich.edu    '''rom_or_macro : rom_block
3294512Sgblack@eecs.umich.edu                    | macroop_def'''
3304483Sgblack@eecs.umich.edu
3314483Sgblack@eecs.umich.edu# Defines a section of microcode that should go in the current ROM
3324483Sgblack@eecs.umich.edudef p_rom_block(t):
3334483Sgblack@eecs.umich.edu    'rom_block : DEF ROM block SEMI'
3344507Sgblack@eecs.umich.edu    if not t.parser.rom:
3354507Sgblack@eecs.umich.edu        print_error("Rom block found, but no Rom object specified.")
3364507Sgblack@eecs.umich.edu        raise TypeError, "Rom block found, but no Rom object was specified."
3374483Sgblack@eecs.umich.edu    for statement in t[3].statements:
3384483Sgblack@eecs.umich.edu        handle_statement(t.parser, t.parser.rom, statement)
3394483Sgblack@eecs.umich.edu    t[0] = t.parser.rom
3404483Sgblack@eecs.umich.edu
3414483Sgblack@eecs.umich.edu# Defines a macroop that jumps to an external label in the ROM
3424483Sgblack@eecs.umich.edudef p_macroop_def_0(t):
3434502Sgblack@eecs.umich.edu    'macroop_def : DEF MACROOP ID LPAREN ID RPAREN SEMI'
3444507Sgblack@eecs.umich.edu    if not t.parser.rom_macroop_type:
3454507Sgblack@eecs.umich.edu        print_error("ROM based macroop found, but no ROM macroop class was specified.")
3464507Sgblack@eecs.umich.edu        raise TypeError, "ROM based macroop found, but no ROM macroop class was specified."
3474507Sgblack@eecs.umich.edu    macroop = t.parser.rom_macroop_type(t[3], t[5])
3484508Sgblack@eecs.umich.edu    t.parser.macroops[t[3]] = macroop
3494507Sgblack@eecs.umich.edu
3504483Sgblack@eecs.umich.edu
3514483Sgblack@eecs.umich.edu# Defines a macroop that is combinationally generated
3524483Sgblack@eecs.umich.edudef p_macroop_def_1(t):
3534483Sgblack@eecs.umich.edu    'macroop_def : DEF MACROOP ID block SEMI'
3544483Sgblack@eecs.umich.edu    try:
3554483Sgblack@eecs.umich.edu        curop = t.parser.macro_type(t[3])
3564483Sgblack@eecs.umich.edu    except TypeError:
3574483Sgblack@eecs.umich.edu        print_error("Error creating macroop object.")
3584483Sgblack@eecs.umich.edu        raise
3594483Sgblack@eecs.umich.edu    for statement in t[4].statements:
3604483Sgblack@eecs.umich.edu        handle_statement(t.parser, curop, statement)
3614502Sgblack@eecs.umich.edu    t.parser.macroops[t[3]] = curop
3624483Sgblack@eecs.umich.edu
3634512Sgblack@eecs.umich.edu# A block of statements
3644512Sgblack@eecs.umich.edudef p_block(t):
3654512Sgblack@eecs.umich.edu    'block : LBRACE statements RBRACE'
3664512Sgblack@eecs.umich.edu    block = Block()
3674512Sgblack@eecs.umich.edu    block.statements = t[2]
3684512Sgblack@eecs.umich.edu    t[0] = block
3694512Sgblack@eecs.umich.edu
3704483Sgblack@eecs.umich.edudef p_statements_0(t):
3714483Sgblack@eecs.umich.edu    'statements : statement'
3724483Sgblack@eecs.umich.edu    if t[1]:
3734483Sgblack@eecs.umich.edu        t[0] = [t[1]]
3744483Sgblack@eecs.umich.edu    else:
3754483Sgblack@eecs.umich.edu        t[0] = []
3764483Sgblack@eecs.umich.edu
3774483Sgblack@eecs.umich.edudef p_statements_1(t):
3784483Sgblack@eecs.umich.edu    'statements : statements statement'
3794483Sgblack@eecs.umich.edu    if t[2]:
3804483Sgblack@eecs.umich.edu        t[1].append(t[2])
3814483Sgblack@eecs.umich.edu    t[0] = t[1]
3824483Sgblack@eecs.umich.edu
3834483Sgblack@eecs.umich.edudef p_statement(t):
3844483Sgblack@eecs.umich.edu    'statement : content_of_statement end_of_statement'
3854483Sgblack@eecs.umich.edu    t[0] = t[1]
3864483Sgblack@eecs.umich.edu
3874483Sgblack@eecs.umich.edu# A statement can be a microop or an assembler directive
3884483Sgblack@eecs.umich.edudef p_content_of_statement_0(t):
3894483Sgblack@eecs.umich.edu    '''content_of_statement : microop
3904483Sgblack@eecs.umich.edu                            | directive'''
3914483Sgblack@eecs.umich.edu    t[0] = t[1]
3924483Sgblack@eecs.umich.edu
3934512Sgblack@eecs.umich.edu# Ignore empty statements
3944483Sgblack@eecs.umich.edudef p_content_of_statement_1(t):
3954483Sgblack@eecs.umich.edu    'content_of_statement : '
3964483Sgblack@eecs.umich.edu    pass
3974483Sgblack@eecs.umich.edu
3984483Sgblack@eecs.umich.edu# Statements are ended by newlines or a semi colon
3994483Sgblack@eecs.umich.edudef p_end_of_statement(t):
4004483Sgblack@eecs.umich.edu    '''end_of_statement : NEWLINE
4014483Sgblack@eecs.umich.edu                        | SEMI'''
4024483Sgblack@eecs.umich.edu    pass
4034483Sgblack@eecs.umich.edu
4044512Sgblack@eecs.umich.edu# Different flavors of microop to avoid shift/reduce errors
4054483Sgblack@eecs.umich.edudef p_microop_0(t):
4064483Sgblack@eecs.umich.edu    'microop : labels ID'
4074483Sgblack@eecs.umich.edu    microop = Microop()
4084483Sgblack@eecs.umich.edu    microop.labels = t[1]
4094483Sgblack@eecs.umich.edu    microop.mnemonic = t[2]
4104483Sgblack@eecs.umich.edu    t[0] = microop
4114483Sgblack@eecs.umich.edu
4124483Sgblack@eecs.umich.edudef p_microop_1(t):
4134483Sgblack@eecs.umich.edu    'microop : ID'
4144483Sgblack@eecs.umich.edu    microop = Microop()
4154483Sgblack@eecs.umich.edu    microop.mnemonic = t[1]
4164483Sgblack@eecs.umich.edu    t[0] = microop
4174483Sgblack@eecs.umich.edu
4184483Sgblack@eecs.umich.edudef p_microop_2(t):
4194483Sgblack@eecs.umich.edu    'microop : labels ID PARAMS'
4204483Sgblack@eecs.umich.edu    microop = Microop()
4214483Sgblack@eecs.umich.edu    microop.labels = t[1]
4224483Sgblack@eecs.umich.edu    microop.mnemonic = t[2]
4234483Sgblack@eecs.umich.edu    microop.params = t[3]
4244483Sgblack@eecs.umich.edu    t[0] = microop
4254483Sgblack@eecs.umich.edu
4264483Sgblack@eecs.umich.edudef p_microop_3(t):
4274483Sgblack@eecs.umich.edu    'microop : ID PARAMS'
4284483Sgblack@eecs.umich.edu    microop = Microop()
4294483Sgblack@eecs.umich.edu    microop.mnemonic = t[1]
4304483Sgblack@eecs.umich.edu    microop.params = t[2]
4314483Sgblack@eecs.umich.edu    t[0] = microop
4324483Sgblack@eecs.umich.edu
4334512Sgblack@eecs.umich.edu# Labels in the microcode
4344483Sgblack@eecs.umich.edudef p_labels_0(t):
4354483Sgblack@eecs.umich.edu    'labels : label'
4364483Sgblack@eecs.umich.edu    t[0] = [t[1]]
4374483Sgblack@eecs.umich.edu
4384483Sgblack@eecs.umich.edudef p_labels_1(t):
4394483Sgblack@eecs.umich.edu    'labels : labels label'
4404483Sgblack@eecs.umich.edu    t[1].append(t[2])
4414483Sgblack@eecs.umich.edu    t[0] = t[1]
4424483Sgblack@eecs.umich.edu
4435009Sgblack@eecs.umich.edu# labels on lines by themselves are attached to the following instruction.
4445009Sgblack@eecs.umich.edudef p_labels_2(t):
4455009Sgblack@eecs.umich.edu    'labels : labels NEWLINE'
4465009Sgblack@eecs.umich.edu    t[0] = t[1]
4475009Sgblack@eecs.umich.edu
4484483Sgblack@eecs.umich.edudef p_label_0(t):
4494483Sgblack@eecs.umich.edu    'label : ID COLON'
4504483Sgblack@eecs.umich.edu    label = Label()
4514483Sgblack@eecs.umich.edu    label.is_extern = False
4524483Sgblack@eecs.umich.edu    label.text = t[1]
4534483Sgblack@eecs.umich.edu    t[0] = label
4544483Sgblack@eecs.umich.edu
4554483Sgblack@eecs.umich.edudef p_label_1(t):
4564483Sgblack@eecs.umich.edu    'label : EXTERN ID COLON'
4574483Sgblack@eecs.umich.edu    label = Label()
4584483Sgblack@eecs.umich.edu    label.is_extern = True
4594483Sgblack@eecs.umich.edu    label.text = t[2]
4604483Sgblack@eecs.umich.edu    t[0] = label
4614483Sgblack@eecs.umich.edu
4624512Sgblack@eecs.umich.edu# Directives for the macroop
4634503Sgblack@eecs.umich.edudef p_directive_0(t):
4644483Sgblack@eecs.umich.edu    'directive : DOT ID'
4654483Sgblack@eecs.umich.edu    directive = Directive()
4664483Sgblack@eecs.umich.edu    directive.name = t[2]
4674483Sgblack@eecs.umich.edu    t[0] = directive
4684483Sgblack@eecs.umich.edu
4694503Sgblack@eecs.umich.edudef p_directive_1(t):
4704503Sgblack@eecs.umich.edu    'directive : DOT ID PARAMS'
4714503Sgblack@eecs.umich.edu    directive = Directive()
4724503Sgblack@eecs.umich.edu    directive.name = t[2]
4734503Sgblack@eecs.umich.edu    directive.params = t[3]
4744503Sgblack@eecs.umich.edu    t[0] = directive
4754503Sgblack@eecs.umich.edu
4764483Sgblack@eecs.umich.edu# Parse error handler.  Note that the argument here is the offending
4774483Sgblack@eecs.umich.edu# *token*, not a grammar symbol (hence the need to use t.value)
4784483Sgblack@eecs.umich.edudef p_error(t):
4794483Sgblack@eecs.umich.edu    if t:
4804483Sgblack@eecs.umich.edu        error(t.lineno, "syntax error at '%s'" % t.value)
4814483Sgblack@eecs.umich.edu    else:
4824483Sgblack@eecs.umich.edu        error(0, "unknown syntax error", True)
4834483Sgblack@eecs.umich.edu
4844483Sgblack@eecs.umich.educlass MicroAssembler(object):
4854483Sgblack@eecs.umich.edu
4864507Sgblack@eecs.umich.edu    def __init__(self, macro_type, microops,
4874507Sgblack@eecs.umich.edu            rom = None, rom_macroop_type = None):
4884483Sgblack@eecs.umich.edu        self.lexer = lex.lex()
4894483Sgblack@eecs.umich.edu        self.parser = yacc.yacc()
4904483Sgblack@eecs.umich.edu        self.parser.macro_type = macro_type
4914502Sgblack@eecs.umich.edu        self.parser.macroops = {}
4924483Sgblack@eecs.umich.edu        self.parser.microops = microops
4934483Sgblack@eecs.umich.edu        self.parser.rom = rom
4944507Sgblack@eecs.umich.edu        self.parser.rom_macroop_type = rom_macroop_type
4954613Sgblack@eecs.umich.edu        self.parser.symbols = {}
4964613Sgblack@eecs.umich.edu        self.symbols = self.parser.symbols
4974483Sgblack@eecs.umich.edu
4984483Sgblack@eecs.umich.edu    def assemble(self, asm):
4994483Sgblack@eecs.umich.edu        self.parser.parse(asm, lexer=self.lexer)
5004483Sgblack@eecs.umich.edu        macroops = self.parser.macroops
5014502Sgblack@eecs.umich.edu        self.parser.macroops = {}
5024483Sgblack@eecs.umich.edu        return macroops
503