micro_asm.py revision 4613
1360SN/A# Copyright (c) 2003-2005 The Regents of The University of Michigan
21458SN/A# All rights reserved.
3360SN/A#
4360SN/A# Redistribution and use in source and binary forms, with or without
5360SN/A# modification, are permitted provided that the following conditions are
6360SN/A# met: redistributions of source code must retain the above copyright
7360SN/A# notice, this list of conditions and the following disclaimer;
8360SN/A# redistributions in binary form must reproduce the above copyright
9360SN/A# notice, this list of conditions and the following disclaimer in the
10360SN/A# documentation and/or other materials provided with the distribution;
11360SN/A# neither the name of the copyright holders nor the names of its
12360SN/A# contributors may be used to endorse or promote products derived from
13360SN/A# this software without specific prior written permission.
14360SN/A#
15360SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16360SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17360SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18360SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19360SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20360SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21360SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22360SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23360SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24360SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25360SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26360SN/A#
272665Ssaidi@eecs.umich.edu# Authors: Gabe Black
282665Ssaidi@eecs.umich.edu
292665Ssaidi@eecs.umich.eduimport os
30360SN/Aimport sys
31360SN/Aimport re
3211793Sbrandon.potter@amd.comimport string
3311793Sbrandon.potter@amd.comimport traceback
342093SN/A# get type names
3513479Santhony.gutierrez@amd.comfrom types import *
36360SN/A
37360SN/A# Prepend the directory where the PLY lex & yacc modules are found
3811911SBrandon.Potter@amd.com# to the search path.
396712Snate@binkert.orgsys.path[0:0] = [os.environ['M5_PLY']]
4013031Sbrandon.potter@amd.com
41360SN/Afrom ply import lex
42360SN/Afrom ply import yacc
437680Sgblack@eecs.umich.edu
442474SN/A##########################################################################
45360SN/A#
466658Snate@binkert.org# Base classes for use outside of the assembler
472680Sktlim@umich.edu#
4812716Smichael.lebeane@amd.com##########################################################################
492474SN/A
5013031Sbrandon.potter@amd.comclass Micro_Container(object):
51360SN/A    def __init__(self, name):
528229Snate@binkert.org        self.microops = []
5311794Sbrandon.potter@amd.com        self.name = name
5411794Sbrandon.potter@amd.com        self.directives = {}
556029Ssteve.reinhardt@amd.com        self.micro_classes = {}
56360SN/A        self.labels = {}
57360SN/A
582107SN/A    def add_microop(self, microop):
59360SN/A        self.microops.append(microop)
6013933Sbrandon.potter@amd.com
6113933Sbrandon.potter@amd.com    def __str__(self):
6213933Sbrandon.potter@amd.com        string = "%s:\n" % self.name
6313933Sbrandon.potter@amd.com        for microop in self.microops:
6413933Sbrandon.potter@amd.com            string += "  %s\n" % microop
6513933Sbrandon.potter@amd.com        return string
661450SN/A
6713995Sbrandon.potter@amd.comclass Combinational_Macroop(Micro_Container):
68360SN/A    pass
6911794Sbrandon.potter@amd.com
702484SN/Aclass Rom_Macroop(object):
712484SN/A    def __init__(self, name, target):
72360SN/A        self.name = name
73360SN/A        self.target = target
74360SN/A
751450SN/A    def __str__(self):
7613995Sbrandon.potter@amd.com        return "%s: %s\n" % (self.name, self.target)
77360SN/A
7811794Sbrandon.potter@amd.comclass Rom(Micro_Container):
7911794Sbrandon.potter@amd.com    def __init__(self, name):
8011794Sbrandon.potter@amd.com        super(Rom, self).__init__(name)
8110831Ssteve.reinhardt@amd.com        self.externs = {}
82360SN/A
838149SChris.Emmons@ARM.com##########################################################################
848149SChris.Emmons@ARM.com#
858149SChris.Emmons@ARM.com# Support classes
8611886Sbrandon.potter@amd.com#
8711911SBrandon.Potter@amd.com##########################################################################
8811886Sbrandon.potter@amd.com
8911911SBrandon.Potter@amd.comclass Label(object):
9011911SBrandon.Potter@amd.com    def __init__(self):
9111911SBrandon.Potter@amd.com        self.extern = False
9211911SBrandon.Potter@amd.com        self.name = ""
9314024Sgabeblack@google.com
9411886Sbrandon.potter@amd.comclass Block(object):
9511911SBrandon.Potter@amd.com    def __init__(self):
9611911SBrandon.Potter@amd.com        self.statements = []
9711911SBrandon.Potter@amd.com
9811911SBrandon.Potter@amd.comclass Statement(object):
9911911SBrandon.Potter@amd.com    def __init__(self):
10011911SBrandon.Potter@amd.com        self.is_microop = False
10113995Sbrandon.potter@amd.com        self.is_directive = False
10211911SBrandon.Potter@amd.com        self.params = ""
10311911SBrandon.Potter@amd.com
10413995Sbrandon.potter@amd.comclass Microop(Statement):
10511911SBrandon.Potter@amd.com    def __init__(self):
10611911SBrandon.Potter@amd.com        super(Microop, self).__init__()
10711911SBrandon.Potter@amd.com        self.mnemonic = ""
10811911SBrandon.Potter@amd.com        self.labels = []
10911911SBrandon.Potter@amd.com        self.is_microop = True
11011911SBrandon.Potter@amd.com
11111911SBrandon.Potter@amd.comclass Directive(Statement):
11211911SBrandon.Potter@amd.com    def __init__(self):
11311911SBrandon.Potter@amd.com        super(Directive, self).__init__()
11411911SBrandon.Potter@amd.com        self.name = ""
11511911SBrandon.Potter@amd.com        self.is_directive = True
11611911SBrandon.Potter@amd.com
11711911SBrandon.Potter@amd.com##########################################################################
11811911SBrandon.Potter@amd.com#
11911911SBrandon.Potter@amd.com# Functions that handle common tasks
12011911SBrandon.Potter@amd.com#
12111911SBrandon.Potter@amd.com##########################################################################
12211911SBrandon.Potter@amd.com
12311911SBrandon.Potter@amd.comdef print_error(message):
12411911SBrandon.Potter@amd.com    print
12511911SBrandon.Potter@amd.com    print "*** %s" % message
12611911SBrandon.Potter@amd.com    print
12711911SBrandon.Potter@amd.com
12811911SBrandon.Potter@amd.comdef handle_statement(parser, container, statement):
12911911SBrandon.Potter@amd.com    if statement.is_microop:
13011911SBrandon.Potter@amd.com        if statement.mnemonic not in parser.microops.keys():
13113644Sqtt2@cornell.edu            raise Exception, "Unrecognized mnemonic: %s" % statement.mnemonic
13213644Sqtt2@cornell.edu        parser.symbols["__microopClassFromInsideTheAssembler"] = \
13313644Sqtt2@cornell.edu            parser.microops[statement.mnemonic]
13411911SBrandon.Potter@amd.com        try:
13511911SBrandon.Potter@amd.com            microop = eval('__microopClassFromInsideTheAssembler(%s)' %
13611911SBrandon.Potter@amd.com                    statement.params, {}, parser.symbols)
13711911SBrandon.Potter@amd.com        except:
13811911SBrandon.Potter@amd.com            print_error("Error creating microop object with mnemonic %s." % \
13911911SBrandon.Potter@amd.com                    statement.mnemonic)
14013644Sqtt2@cornell.edu            raise
14113644Sqtt2@cornell.edu        try:
14213644Sqtt2@cornell.edu            for label in statement.labels:
14313644Sqtt2@cornell.edu                container.labels[label.name] = microop
14413644Sqtt2@cornell.edu                if label.extern:
14513644Sqtt2@cornell.edu                    container.externs[label.name] = microop
14613644Sqtt2@cornell.edu            container.add_microop(microop)
14713644Sqtt2@cornell.edu        except:
14813644Sqtt2@cornell.edu            print_error("Error adding microop.")
14913644Sqtt2@cornell.edu            raise
15013644Sqtt2@cornell.edu    elif statement.is_directive:
15113644Sqtt2@cornell.edu        if statement.name not in container.directives.keys():
15213644Sqtt2@cornell.edu            raise Exception, "Unrecognized directive: %s" % statement.name
15313644Sqtt2@cornell.edu        parser.symbols["__directiveFunctionFromInsideTheAssembler"] = \
15413644Sqtt2@cornell.edu            container.directives[statement.name]
15513644Sqtt2@cornell.edu        try:
15613644Sqtt2@cornell.edu            eval('__directiveFunctionFromInsideTheAssembler(%s)' %
15713644Sqtt2@cornell.edu                    statement.params, {}, parser.symbols)
15813644Sqtt2@cornell.edu        except:
15911911SBrandon.Potter@amd.com            print_error("Error executing directive.")
16011911SBrandon.Potter@amd.com            print container.directives
16111911SBrandon.Potter@amd.com            raise
16211911SBrandon.Potter@amd.com    else:
16311911SBrandon.Potter@amd.com        raise Exception, "Didn't recognize the type of statement", statement
16411911SBrandon.Potter@amd.com
16511911SBrandon.Potter@amd.com##########################################################################
16611911SBrandon.Potter@amd.com#
16711911SBrandon.Potter@amd.com# Lexer specification
16811911SBrandon.Potter@amd.com#
16911911SBrandon.Potter@amd.com##########################################################################
17011911SBrandon.Potter@amd.com
17111886Sbrandon.potter@amd.com# Error handler.  Just call exit.  Output formatted to work under
17211886Sbrandon.potter@amd.com# Emacs compile-mode.  Optional 'print_traceback' arg, if set to True,
17311911SBrandon.Potter@amd.com# prints a Python stack backtrace too (can be handy when trying to
17411911SBrandon.Potter@amd.com# debug the parser itself).
17511911SBrandon.Potter@amd.comdef error(lineno, string, print_traceback = False):
17611911SBrandon.Potter@amd.com    # Print a Python stack backtrace if requested.
17711911SBrandon.Potter@amd.com    if (print_traceback):
17811911SBrandon.Potter@amd.com        traceback.print_exc()
17911911SBrandon.Potter@amd.com    if lineno != 0:
18011911SBrandon.Potter@amd.com        line_str = "%d:" % lineno
18111911SBrandon.Potter@amd.com    else:
18211911SBrandon.Potter@amd.com        line_str = ""
18311911SBrandon.Potter@amd.com    sys.exit("%s %s" % (line_str, string))
18411911SBrandon.Potter@amd.com
18511911SBrandon.Potter@amd.comreserved = ('DEF', 'MACROOP', 'ROM', 'EXTERN')
18611911SBrandon.Potter@amd.com
18711911SBrandon.Potter@amd.comtokens = reserved + (
18811911SBrandon.Potter@amd.com        # identifier
18911911SBrandon.Potter@amd.com        'ID',
19011911SBrandon.Potter@amd.com        # arguments for microops and directives
19111911SBrandon.Potter@amd.com        'PARAMS',
19213644Sqtt2@cornell.edu
19313644Sqtt2@cornell.edu        'LPAREN', 'RPAREN',
19413644Sqtt2@cornell.edu        'LBRACE', 'RBRACE',
19513644Sqtt2@cornell.edu        'COLON', 'SEMI', 'DOT',
19613644Sqtt2@cornell.edu        'NEWLINE'
19713644Sqtt2@cornell.edu        )
19813644Sqtt2@cornell.edu
19913644Sqtt2@cornell.edu# New lines are ignored at the top level, but they end statements in the
20013644Sqtt2@cornell.edu# assembler
20113644Sqtt2@cornell.edustates = (
20213644Sqtt2@cornell.edu    ('asm', 'exclusive'),
20313644Sqtt2@cornell.edu    ('params', 'exclusive'),
20413644Sqtt2@cornell.edu)
20513644Sqtt2@cornell.edu
20613644Sqtt2@cornell.edureserved_map = { }
20713644Sqtt2@cornell.edufor r in reserved:
20813644Sqtt2@cornell.edu    reserved_map[r.lower()] = r
20913644Sqtt2@cornell.edu
21013644Sqtt2@cornell.edu# Ignore comments
21113644Sqtt2@cornell.edudef t_ANY_COMMENT(t):
21213644Sqtt2@cornell.edu    r'\#[^\n]*(?=\n)'
21313644Sqtt2@cornell.edu
21413644Sqtt2@cornell.edudef t_ANY_MULTILINECOMMENT(t):
21513644Sqtt2@cornell.edu    r'/\*([^/]|((?<!\*)/))*\*/'
21613644Sqtt2@cornell.edu
21713644Sqtt2@cornell.edu# A colon marks the end of a label. It should follow an ID which will
21813644Sqtt2@cornell.edu# put the lexer in the "params" state. Seeing the colon will put it back
21911911SBrandon.Potter@amd.com# in the "asm" state since it knows it saw a label and not a mnemonic.
22011886Sbrandon.potter@amd.comdef t_params_COLON(t):
2218149SChris.Emmons@ARM.com    r':'
2228149SChris.Emmons@ARM.com    t.lexer.begin('asm')
22313995Sbrandon.potter@amd.com    return t
224360SN/A
22513995Sbrandon.potter@amd.com# Parameters are a string of text which don't contain an unescaped statement
226360SN/A# statement terminator, ie a newline or semi colon.
227360SN/Adef t_params_PARAMS(t):
2281450SN/A    r'([^\n;\\]|(\\[\n;\\]))+'
22913995Sbrandon.potter@amd.com    t.lineno += t.value.count('\n')
2306109Ssanchezd@stanford.edu    unescapeParamsRE = re.compile(r'(\\[\n;\\])')
23113995Sbrandon.potter@amd.com    def unescapeParams(mo):
2326109Ssanchezd@stanford.edu        val = mo.group(0)
2336109Ssanchezd@stanford.edu        return val[1]
2346109Ssanchezd@stanford.edu    t.value = unescapeParamsRE.sub(unescapeParams, t.value)
23513995Sbrandon.potter@amd.com    t.lexer.begin('asm')
236360SN/A    return t
23710318Sandreas.hansson@arm.com
238360SN/A# An "ID" in the micro assembler is either a label, directive, or mnemonic
239360SN/A# If it's either a directive or a mnemonic, it will be optionally followed by
240360SN/A# parameters. If it's a label, the following colon will make the lexer stop
2411450SN/A# looking for parameters.
24213995Sbrandon.potter@amd.comdef t_asm_ID(t):
243360SN/A    r'[A-Za-z_]\w*'
244360SN/A    t.type = reserved_map.get(t.value, 'ID')
2456701Sgblack@eecs.umich.edu    t.lexer.begin('params')
24613995Sbrandon.potter@amd.com    return t
2476701Sgblack@eecs.umich.edu
2485748SSteve.Reinhardt@amd.com# If there is a label and you're -not- in the assembler (which would be caught
24911905SBrandon.Potter@amd.com# above), don't start looking for parameters.
25011905SBrandon.Potter@amd.comdef t_ANY_ID(t):
25111905SBrandon.Potter@amd.com    r'[A-Za-z_]\w*'
2525748SSteve.Reinhardt@amd.com    t.type = reserved_map.get(t.value, 'ID')
2535748SSteve.Reinhardt@amd.com    return t
2545748SSteve.Reinhardt@amd.com
25511905SBrandon.Potter@amd.com# Braces enter and exit micro assembly
2565748SSteve.Reinhardt@amd.comdef t_INITIAL_LBRACE(t):
25711905SBrandon.Potter@amd.com    r'\{'
2585748SSteve.Reinhardt@amd.com    t.lexer.begin('asm')
25911905SBrandon.Potter@amd.com    return t
26011905SBrandon.Potter@amd.com
26110318Sandreas.hansson@arm.comdef t_asm_RBRACE(t):
2625748SSteve.Reinhardt@amd.com    r'\}'
26310318Sandreas.hansson@arm.com    t.lexer.begin('INITIAL')
2646687Stjones1@inf.ed.ac.uk    return t
2656687Stjones1@inf.ed.ac.uk
2666687Stjones1@inf.ed.ac.uk# At the top level, keep track of newlines only for line counting.
26711905SBrandon.Potter@amd.comdef t_INITIAL_NEWLINE(t):
26814024Sgabeblack@google.com    r'\n+'
2696687Stjones1@inf.ed.ac.uk    t.lineno += t.value.count('\n')
2706687Stjones1@inf.ed.ac.uk
27110318Sandreas.hansson@arm.com# In the micro assembler, do line counting but also return a token. The
2726687Stjones1@inf.ed.ac.uk# token is needed by the parser to detect the end of a statement.
2738852Sandreas.hansson@arm.comdef t_asm_NEWLINE(t):
27410318Sandreas.hansson@arm.com    r'\n+'
2756687Stjones1@inf.ed.ac.uk    t.lineno += t.value.count('\n')
27611906SBrandon.Potter@amd.com    return t
27710318Sandreas.hansson@arm.com
2788852Sandreas.hansson@arm.com# A newline or semi colon when looking for params signals that the statement
2796687Stjones1@inf.ed.ac.uk# is over and the lexer should go back to looking for regular assembly.
2806687Stjones1@inf.ed.ac.ukdef t_params_NEWLINE(t):
2812474SN/A    r'\n+'
2821450SN/A    t.lineno += t.value.count('\n')
2835748SSteve.Reinhardt@amd.com    t.lexer.begin('asm')
28411905SBrandon.Potter@amd.com    return t
28511380Salexandru.dutu@amd.com
28611905SBrandon.Potter@amd.comdef t_params_SEMI(t):
28711905SBrandon.Potter@amd.com    r';'
288360SN/A    t.lexer.begin('asm')
289360SN/A    return t
29011886Sbrandon.potter@amd.com
29113995Sbrandon.potter@amd.com# Basic regular expressions to pick out simple tokens
29211886Sbrandon.potter@amd.comt_ANY_LPAREN = r'\('
29311886Sbrandon.potter@amd.comt_ANY_RPAREN = r'\)'
29413995Sbrandon.potter@amd.comt_ANY_SEMI   = r';'
29511886Sbrandon.potter@amd.comt_ANY_DOT    = r'\.'
29611886Sbrandon.potter@amd.com
29711886Sbrandon.potter@amd.comt_ANY_ignore = ' \t\x0c'
29811886Sbrandon.potter@amd.com
29911886Sbrandon.potter@amd.comdef t_ANY_error(t):
300360SN/A    error(t.lineno, "illegal character '%s'" % t.value[0])
3011450SN/A    t.skip(1)
30213995Sbrandon.potter@amd.com
303360SN/A##########################################################################
3046701Sgblack@eecs.umich.edu#
30513995Sbrandon.potter@amd.com# Parser specification
30610931Sbrandon.potter@amd.com#
30710931Sbrandon.potter@amd.com##########################################################################
30811856Sbrandon.potter@amd.com
309360SN/A# Start symbol for a file which may have more than one macroop or rom
310360SN/A# specification.
3111450SN/Adef p_file(t):
31213995Sbrandon.potter@amd.com    'file : opt_rom_or_macros'
313360SN/A
3146701Sgblack@eecs.umich.edudef p_opt_rom_or_macros_0(t):
31513995Sbrandon.potter@amd.com    'opt_rom_or_macros : '
31610931Sbrandon.potter@amd.com
3176701Sgblack@eecs.umich.edudef p_opt_rom_or_macros_1(t):
3186701Sgblack@eecs.umich.edu    'opt_rom_or_macros : rom_or_macros'
319360SN/A
32011856Sbrandon.potter@amd.comdef p_rom_or_macros_0(t):
32111856Sbrandon.potter@amd.com    'rom_or_macros : rom_or_macro'
32210931Sbrandon.potter@amd.com
32311856Sbrandon.potter@amd.comdef p_rom_or_macros_1(t):
32410931Sbrandon.potter@amd.com    'rom_or_macros : rom_or_macros rom_or_macro'
32510931Sbrandon.potter@amd.com
326360SN/Adef p_rom_or_macro_0(t):
3271458SN/A    '''rom_or_macro : rom_block
328360SN/A                    | macroop_def'''
329360SN/A
330360SN/A# Defines a section of microcode that should go in the current ROM
3311450SN/Adef p_rom_block(t):
33213995Sbrandon.potter@amd.com    'rom_block : DEF ROM block SEMI'
3334118Sgblack@eecs.umich.edu    if not t.parser.rom:
3346701Sgblack@eecs.umich.edu        print_error("Rom block found, but no Rom object specified.")
33513995Sbrandon.potter@amd.com        raise TypeError, "Rom block found, but no Rom object was specified."
33610931Sbrandon.potter@amd.com    for statement in t[3].statements:
3376701Sgblack@eecs.umich.edu        handle_statement(t.parser, t.parser.rom, statement)
3386701Sgblack@eecs.umich.edu    t[0] = t.parser.rom
3396701Sgblack@eecs.umich.edu
3406701Sgblack@eecs.umich.edu# Defines a macroop that jumps to an external label in the ROM
3414118Sgblack@eecs.umich.edudef p_macroop_def_0(t):
34211856Sbrandon.potter@amd.com    'macroop_def : DEF MACROOP ID LPAREN ID RPAREN SEMI'
34311856Sbrandon.potter@amd.com    if not t.parser.rom_macroop_type:
34410931Sbrandon.potter@amd.com        print_error("ROM based macroop found, but no ROM macroop class was specified.")
34511856Sbrandon.potter@amd.com        raise TypeError, "ROM based macroop found, but no ROM macroop class was specified."
34610931Sbrandon.potter@amd.com    macroop = t.parser.rom_macroop_type(t[3], t[5])
3474118Sgblack@eecs.umich.edu    t.parser.macroops[t[3]] = macroop
3484118Sgblack@eecs.umich.edu
34910931Sbrandon.potter@amd.com
3504118Sgblack@eecs.umich.edu# Defines a macroop that is combinationally generated
3514118Sgblack@eecs.umich.edudef p_macroop_def_1(t):
35211379Sbrandon.potter@amd.com    'macroop_def : DEF MACROOP ID block SEMI'
3534118Sgblack@eecs.umich.edu    try:
35411379Sbrandon.potter@amd.com        curop = t.parser.macro_type(t[3])
35511379Sbrandon.potter@amd.com    except TypeError:
35611379Sbrandon.potter@amd.com        print_error("Error creating macroop object.")
35714024Sgabeblack@google.com        raise
35811379Sbrandon.potter@amd.com    for statement in t[4].statements:
3594118Sgblack@eecs.umich.edu        handle_statement(t.parser, curop, statement)
3604118Sgblack@eecs.umich.edu    t.parser.macroops[t[3]] = curop
3614118Sgblack@eecs.umich.edu
3624118Sgblack@eecs.umich.edu# A block of statements
36313995Sbrandon.potter@amd.comdef p_block(t):
364360SN/A    'block : LBRACE statements RBRACE'
36511383Sbrandon.potter@amd.com    block = Block()
36611383Sbrandon.potter@amd.com    block.statements = t[2]
36711383Sbrandon.potter@amd.com    t[0] = block
3681458SN/A
369360SN/Adef p_statements_0(t):
370360SN/A    'statements : statement'
371360SN/A    if t[1]:
372360SN/A        t[0] = [t[1]]
373360SN/A    else:
3741450SN/A        t[0] = []
37513995Sbrandon.potter@amd.com
376360SN/Adef p_statements_1(t):
3776701Sgblack@eecs.umich.edu    'statements : statements statement'
37813995Sbrandon.potter@amd.com    if t[2]:
37911906SBrandon.Potter@amd.com        t[1].append(t[2])
3806701Sgblack@eecs.umich.edu    t[0] = t[1]
38111906SBrandon.Potter@amd.com
382360SN/Adef p_statement(t):
383360SN/A    'statement : content_of_statement end_of_statement'
384360SN/A    t[0] = t[1]
38514024Sgabeblack@google.com
386360SN/A# A statement can be a microop or an assembler directive
3871458SN/Adef p_content_of_statement_0(t):
388360SN/A    '''content_of_statement : microop
389360SN/A                            | directive'''
3901450SN/A    t[0] = t[1]
39113995Sbrandon.potter@amd.com
3925513SMichael.Adler@intel.com# Ignore empty statements
3935513SMichael.Adler@intel.comdef p_content_of_statement_1(t):
3946731Svince@csl.cornell.edu    'content_of_statement : '
39513995Sbrandon.potter@amd.com    pass
39611906SBrandon.Potter@amd.com
3976701Sgblack@eecs.umich.edu# Statements are ended by newlines or a semi colon
39811906SBrandon.Potter@amd.comdef p_end_of_statement(t):
3995513SMichael.Adler@intel.com    '''end_of_statement : NEWLINE
4005513SMichael.Adler@intel.com                        | SEMI'''
40113883Sdavid.hashe@amd.com    pass
4025513SMichael.Adler@intel.com
4035513SMichael.Adler@intel.com# Different flavors of microop to avoid shift/reduce errors
4045513SMichael.Adler@intel.comdef p_microop_0(t):
4055513SMichael.Adler@intel.com    'microop : labels ID'
4065513SMichael.Adler@intel.com    microop = Microop()
4075513SMichael.Adler@intel.com    microop.labels = t[1]
4085513SMichael.Adler@intel.com    microop.mnemonic = t[2]
40910955Sdavid.hashe@amd.com    t[0] = microop
41011856Sbrandon.potter@amd.com
4115513SMichael.Adler@intel.comdef p_microop_1(t):
41210955Sdavid.hashe@amd.com    'microop : ID'
4135513SMichael.Adler@intel.com    microop = Microop()
4145513SMichael.Adler@intel.com    microop.mnemonic = t[1]
4155513SMichael.Adler@intel.com    t[0] = microop
4165513SMichael.Adler@intel.com
41714024Sgabeblack@google.comdef p_microop_2(t):
4185513SMichael.Adler@intel.com    'microop : labels ID PARAMS'
4195513SMichael.Adler@intel.com    microop = Microop()
4205513SMichael.Adler@intel.com    microop.labels = t[1]
4215513SMichael.Adler@intel.com    microop.mnemonic = t[2]
42210203SAli.Saidi@ARM.com    microop.params = t[3]
42313995Sbrandon.potter@amd.com    t[0] = microop
42410203SAli.Saidi@ARM.com
42513995Sbrandon.potter@amd.comdef p_microop_3(t):
42610203SAli.Saidi@ARM.com    'microop : ID PARAMS'
4275513SMichael.Adler@intel.com    microop = Microop()
4285513SMichael.Adler@intel.com    microop.mnemonic = t[1]
42913995Sbrandon.potter@amd.com    microop.params = t[2]
4305513SMichael.Adler@intel.com    t[0] = microop
4315513SMichael.Adler@intel.com
43213995Sbrandon.potter@amd.com# Labels in the microcode
4335513SMichael.Adler@intel.comdef p_labels_0(t):
43414024Sgabeblack@google.com    'labels : label'
43510223Ssteve.reinhardt@amd.com    t[0] = [t[1]]
4365513SMichael.Adler@intel.com
43713883Sdavid.hashe@amd.comdef p_labels_1(t):
43813883Sdavid.hashe@amd.com    'labels : labels label'
4395513SMichael.Adler@intel.com    t[1].append(t[2])
44011906SBrandon.Potter@amd.com    t[0] = t[1]
4416701Sgblack@eecs.umich.edu
4426701Sgblack@eecs.umich.edudef p_label_0(t):
44311906SBrandon.Potter@amd.com    'label : ID COLON'
4445513SMichael.Adler@intel.com    label = Label()
44510955Sdavid.hashe@amd.com    label.is_extern = False
44610955Sdavid.hashe@amd.com    label.text = t[1]
44710955Sdavid.hashe@amd.com    t[0] = label
44810955Sdavid.hashe@amd.com
44911140Sjthestness@gmail.comdef p_label_1(t):
45011140Sjthestness@gmail.com    'label : EXTERN ID COLON'
45111851Sbrandon.potter@amd.com    label = Label()
45211140Sjthestness@gmail.com    label.is_extern = True
45311140Sjthestness@gmail.com    label.text = t[2]
45411140Sjthestness@gmail.com    t[0] = label
45511140Sjthestness@gmail.com
45611140Sjthestness@gmail.com# Directives for the macroop
45711140Sjthestness@gmail.comdef p_directive_0(t):
45811140Sjthestness@gmail.com    'directive : DOT ID'
45911140Sjthestness@gmail.com    directive = Directive()
46011140Sjthestness@gmail.com    directive.name = t[2]
46111140Sjthestness@gmail.com    t[0] = directive
46211140Sjthestness@gmail.com
46311140Sjthestness@gmail.comdef p_directive_1(t):
46411140Sjthestness@gmail.com    'directive : DOT ID PARAMS'
46511140Sjthestness@gmail.com    directive = Directive()
46611140Sjthestness@gmail.com    directive.name = t[2]
46711140Sjthestness@gmail.com    directive.params = t[3]
46811140Sjthestness@gmail.com    t[0] = directive
46911140Sjthestness@gmail.com
47010955Sdavid.hashe@amd.com# Parse error handler.  Note that the argument here is the offending
47110955Sdavid.hashe@amd.com# *token*, not a grammar symbol (hence the need to use t.value)
47210955Sdavid.hashe@amd.comdef p_error(t):
47310955Sdavid.hashe@amd.com    if t:
47411140Sjthestness@gmail.com        error(t.lineno, "syntax error at '%s'" % t.value)
47510955Sdavid.hashe@amd.com    else:
47611140Sjthestness@gmail.com        error(0, "unknown syntax error", True)
47711140Sjthestness@gmail.com
47811140Sjthestness@gmail.comclass MicroAssembler(object):
47911140Sjthestness@gmail.com
48011140Sjthestness@gmail.com    def __init__(self, macro_type, microops,
48110955Sdavid.hashe@amd.com            rom = None, rom_macroop_type = None):
4825513SMichael.Adler@intel.com        self.lexer = lex.lex()
48314024Sgabeblack@google.com        self.parser = yacc.yacc()
4845513SMichael.Adler@intel.com        self.parser.macro_type = macro_type
4855513SMichael.Adler@intel.com        self.parser.macroops = {}
4865513SMichael.Adler@intel.com        self.parser.microops = microops
4875513SMichael.Adler@intel.com        self.parser.rom = rom
4885513SMichael.Adler@intel.com        self.parser.rom_macroop_type = rom_macroop_type
48913995Sbrandon.potter@amd.com        self.parser.symbols = {}
490511SN/A        self.symbols = self.parser.symbols
49113995Sbrandon.potter@amd.com
49210633Smichaelupton@gmail.com    def assemble(self, asm):
49310633Smichaelupton@gmail.com        self.parser.parse(asm, lexer=self.lexer)
49410633Smichaelupton@gmail.com        macroops = self.parser.macroops
49513995Sbrandon.potter@amd.com        self.parser.macroops = {}
49610633Smichaelupton@gmail.com        return macroops
4971706SN/A