microasm.isa revision 4371:c5003760793e
1// -*- mode:c++ -*-
2
3// Copyright (c) 2007 The Hewlett-Packard Development Company
4// All rights reserved.
5//
6// Redistribution and use of this software in source and binary forms,
7// with or without modification, are permitted provided that the
8// following conditions are met:
9//
10// The software must be used only for Non-Commercial Use which means any
11// use which is NOT directed to receiving any direct monetary
12// compensation for, or commercial advantage from such use.  Illustrative
13// examples of non-commercial use are academic research, personal study,
14// teaching, education and corporate research & development.
15// Illustrative examples of commercial use are distributing products for
16// commercial advantage and providing services using the software for
17// commercial advantage.
18//
19// If you wish to use this software or functionality therein that may be
20// covered by patents for commercial use, please contact:
21//     Director of Intellectual Property Licensing
22//     Office of Strategy and Technology
23//     Hewlett-Packard Company
24//     1501 Page Mill Road
25//     Palo Alto, California  94304
26//
27// Redistributions of source code must retain the above copyright notice,
28// this list of conditions and the following disclaimer.  Redistributions
29// in binary form must reproduce the above copyright notice, this list of
30// conditions and the following disclaimer in the documentation and/or
31// other materials provided with the distribution.  Neither the name of
32// the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
33// contributors may be used to endorse or promote products derived from
34// this software without specific prior written permission.  No right of
35// sublicense is granted herewith.  Derivatives of the software and
36// output created using the software may be prepared, but only for
37// Non-Commercial Uses.  Derivatives of the software may be shared with
38// others provided: (i) the others agree to abide by the list of
39// conditions herein which includes the Non-Commercial Use restrictions;
40// and (ii) such Derivatives of the software include the above copyright
41// notice to acknowledge the contribution from this software where
42// applicable, this list of conditions and the disclaimer below.
43//
44// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
45// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
46// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
47// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
48// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
49// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
50// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
54// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55//
56// Authors: Gabe Black
57
58////////////////////////////////////////////////////////////////////
59//
60//  The microcode assembler
61//
62
63let {{
64    # These are used when setting up microops so that they can specialize their
65    # base class template properly.
66    RegOpType = "RegisterOperand"
67    ImmOpType = "ImmediateOperand"
68}};
69
70let {{
71    class MicroOpStatement(object):
72        def __init__(self):
73            self.className = ''
74            self.label = ''
75            self.args = []
76
77        # This converts a list of python bools into
78        # a comma seperated list of C++ bools.
79        def microFlagsText(self, vals):
80            text = ""
81            for val in vals:
82                if val:
83                    text += ", true"
84                else:
85                    text += ", false"
86            return text
87
88        def getAllocator(self, mnemonic, *microFlags):
89            args = ''
90            signature = "<"
91            emptySig = True
92            for arg in self.args:
93                if not emptySig:
94                    signature += ", "
95                emptySig = False
96                if arg.has_key("operandImm"):
97                    args += ", %s" % arg["operandImm"]
98                    signature += ImmOpType
99                elif arg.has_key("operandReg"):
100                    args += ", %s" % arg["operandReg"]
101                    signature += RegOpType
102                elif arg.has_key("operandLabel"):
103                    raise Exception, "Found a label while creating allocator string."
104                else:
105                    raise Exception, "Unrecognized operand type."
106            signature += ">"
107            return 'new %s%s(machInst, %s%s%s)' % (self.className, signature, mnemonic, self.microFlagsText(microFlags), args)
108}};
109
110let{{
111    def assembleMicro(name, Name, code):
112
113        # This function takes in a block of microcode assembly and returns
114        # a python list of objects which describe it.
115
116        # Keep this around in case we need it later
117        orig_code = code
118        # A list of the statements we've found thus far
119        statements = []
120
121        # Regular expressions to pull each piece of the statement out at a
122        # time. Each expression expects the thing it's looking for to be at
123        # the beginning of the line, so the previous component is stripped
124        # before continuing.
125        labelRe = re.compile(r'^[ \t]*(?P<label>\w\w*)[ \t]:')
126        lineRe = re.compile(r'^(?P<line>..*)(\n|$)')
127        classRe = re.compile(r'^[ \t]*(?P<className>[a-zA-Z_]\w*)')
128        # This recognizes three different flavors of operands:
129        # 1. Raw decimal numbers composed of digits between 0 and 9
130        # 2. Code beginning with "{" and continuing until the first "}"
131        #         ^ This one might need revising
132        # 3. A label, which starts with a capital or small letter, or
133        #    underscore, which is optionally followed by a sequence of
134        #    capital or small letters, underscores, or digts between 0 and 9
135        opRe = re.compile( \
136            r'^[ \t]*((\@(?P<operandLabel0>\w\w*))|' +
137                    r'(\@\{(?P<operandLabel1>[^}]*)\})|' +
138                    r'(\%(?P<operandReg0>\w\w*))|' +
139                    r'(\%\{(?P<operandReg1>[^}]*)\})|' +
140                    r'(\$(?P<operandImm0>\w\w*))|' +
141                    r'(\$\{(?P<operandImm1>[^}]*)\}))')
142        lineMatch = lineRe.search(code)
143        while lineMatch != None:
144            statement = MicroOpStatement()
145            # Get a line and seperate it from the rest of the code
146            line = lineMatch.group("line")
147            orig_line = line
148            #print "Parsing line %s" % line
149            code = lineRe.sub('', code, 1)
150
151            # Find the label, if any
152            labelMatch = labelRe.search(line)
153            if labelMatch != None:
154                statement.label = labelMatch.group("label")
155                #print "Found label %s." % statement.label
156            # Clear the label from the statement
157            line = labelRe.sub('', line, 1)
158
159            # Find the class name which is roughly equivalent to the op name
160            classMatch = classRe.search(line)
161            if classMatch == None:
162                raise Exception, "Couldn't find class name in statement: %s" \
163                        % orig_line
164            else:
165                statement.className = classMatch.group("className")
166                #print "Found class name %s." % statement.className
167
168            # Clear the class name from the statement
169            line = classRe.sub('', line, 1)
170
171            #Find as many arguments as you can
172            statement.args = []
173            opMatch = opRe.search(line)
174            while opMatch is not None:
175                statement.args.append({})
176                # args is a list of dicts which collect different
177                # representations of operand values. Different forms might be
178                # needed in different places, for instance to replace a label
179                # with an offset.
180                for opType in ("operandLabel0", "operandReg0", "operandImm0",
181                               "operandLabel1", "operandReg1", "operandImm1"):
182                    if opMatch.group(opType):
183                        statement.args[-1][opType[:-1]] = opMatch.group(opType)
184                if len(statement.args[-1]) == 0:
185                    print "Problem parsing operand in statement: %s" \
186                            % orig_line
187                line = opRe.sub('', line, 1)
188                #print "Found operand %s." % statement.args[-1]
189                opMatch = opRe.search(line)
190            #print "Found operands", statement.args
191
192            # Add this statement to our collection
193            statements.append(statement)
194
195            # Get the next line
196            lineMatch = lineRe.search(code)
197
198        # Decode the labels into displacements
199
200        labels = {}
201        micropc = 0
202        for statement in statements:
203            if statement.label:
204                labels[statement.label] = count
205            micropc += 1
206        micropc = 0
207        for statement in statements:
208            for arg in statement.args:
209                if arg.has_key("operandLabel"):
210                    if not labels.has_key(arg["operandLabel"]):
211                        raise Exception, "Unrecognized label: %s." % arg["operandLabel"]
212                    # This is assuming that intra microcode branches go to
213                    # the next micropc + displacement, or
214                    # micropc + 1 + displacement.
215                    arg["operandImm"] = labels[arg["operandLabel"]] - micropc - 1
216            micropc += 1
217
218        if len(statements) == 0:
219            raise Exception, "Didn't find any microops in microcode: \n%s" % orig_code
220
221        # If we can implement this instruction with exactly one microop, just
222        # use that directly.
223        if len(statements) == 1:
224            decode_block = "return %s;" % \
225                            statements[0].getAllocator('"' + name + '"')
226            return ('', '', decode_block, '')
227        else:
228            # Build a macroop to contain the sequence of microops we've
229            # been given.
230            return genMacroOp(name, Name, statements)
231}};
232