power: Allow voltage to be configured via cmd line
[gem5.git] / src / arch / isa_parser.py
index adadbe14d9fc18ad4555a8a69f28298c1e42a920..749eaf88de8ef8dff7c0317debec020f7e3d2d26 100755 (executable)
@@ -1,5 +1,17 @@
+# Copyright (c) 2014 ARM Limited
+# All rights reserved
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder.  You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
 # Copyright (c) 2003-2005 The Regents of The University of Michigan
-# Copyright (c) 2013 Advanced Micro Devices, Inc.
+# Copyright (c) 2013,2015 Advanced Micro Devices, Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -76,42 +88,17 @@ def fixPythonIndentation(s):
     return s
 
 class ISAParserError(Exception):
-    """Error handler for parser errors"""
+    """Exception class for parser errors"""
     def __init__(self, first, second=None):
         if second is None:
             self.lineno = 0
             self.string = first
         else:
-            if hasattr(first, 'lexer'):
-                first = first.lexer.lineno
             self.lineno = first
             self.string = second
 
-    def display(self, filename_stack, print_traceback=debug):
-        # Output formatted to work under Emacs compile-mode.  Optional
-        # 'print_traceback' arg, if set to True, prints a Python stack
-        # backtrace too (can be handy when trying to debug the parser
-        # itself).
-
-        spaces = ""
-        for (filename, line) in filename_stack[:-1]:
-            print "%sIn file included from %s:" % (spaces, filename)
-            spaces += "  "
-
-        # Print a Python stack backtrace if requested.
-        if print_traceback or not self.lineno:
-            traceback.print_exc()
-
-        line_str = "%s:" % (filename_stack[-1][0], )
-        if self.lineno:
-            line_str += "%d:" % (self.lineno, )
-
-        return "%s%s %s" % (spaces, line_str, self.string)
-
-    def exit(self, filename_stack, print_traceback=debug):
-        # Just call exit.
-
-        sys.exit(self.display(filename_stack, print_traceback))
+    def __str__(self):
+        return self.string
 
 def error(*args):
     raise ISAParserError(*args)
@@ -803,10 +790,8 @@ class MemOperand(Operand):
         return ''
 
     def makeDecl(self):
-        # Note that initializations in the declarations are solely
-        # to avoid 'uninitialized variable' errors from the compiler.
         # Declare memory data variable.
-        return '%s %s = 0;\n' % (self.ctype, self.base_name)
+        return '%s %s;\n' % (self.ctype, self.base_name)
 
     def makeRead(self, predRead):
         if self.read_code != None:
@@ -844,7 +829,9 @@ class PCStateOperand(Operand):
         ctype = 'TheISA::PCState'
         if self.isPCPart():
             ctype = self.ctype
-        return "%s %s;\n" % (ctype, self.base_name)
+        # Note that initializations in the declarations are solely
+        # to avoid 'uninitialized variable' errors from the compiler.
+        return '%s %s = 0;\n' % (ctype, self.base_name)
 
     def isPCState(self):
         return 1
@@ -1008,8 +995,8 @@ class SubOperandList(OperandList):
             # find this op in the master list
             op_desc = master_list.find_base(op_base)
             if not op_desc:
-                error('Found operand %s which is not in the master list!' \
-                      ' This is an internal error' % op_base)
+                error('Found operand %s which is not in the master list!'
+                      % op_base)
             else:
                 # See if we've already found this operand
                 op_desc = self.find_base(op_base)
@@ -1066,9 +1053,14 @@ stringRE = re.compile(r'"([^"\\]|\\.)*"')
 commentRE = re.compile(r'(^)?[^\S\n]*/(?:\*(.*?)\*/[^\S\n]*|/[^\n]*)($)?',
         re.DOTALL | re.MULTILINE)
 
-# Regular expression object to match assignment statements
-# (used in findOperands())
-assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE)
+# Regular expression object to match assignment statements (used in
+# findOperands()).  If the code immediately following the first
+# appearance of the operand matches this regex, then the operand
+# appears to be on the LHS of an assignment, and is thus a
+# destination.  basically we're looking for an '=' that's not '=='.
+# The heinous tangle before that handles the case where the operand
+# has an array subscript.
+assignRE = re.compile(r'(\[[^\]]+\])?\s*=(?!=)', re.MULTILINE)
 
 def makeFlagConstructor(flag_list):
     if len(flag_list) == 0:
@@ -1119,17 +1111,7 @@ class InstObjParams(object):
 
         self.flags = self.operands.concatAttrLists('flags')
 
-        # Make a basic guess on the operand class (function unit type).
-        # These are good enough for most cases, and can be overridden
-        # later otherwise.
-        if 'IsStore' in self.flags:
-            self.op_class = 'MemWriteOp'
-        elif 'IsLoad' in self.flags or 'IsPrefetch' in self.flags:
-            self.op_class = 'MemReadOp'
-        elif 'IsFloating' in self.flags:
-            self.op_class = 'FloatAddOp'
-        else:
-            self.op_class = 'IntAluOp'
+        self.op_class = None
 
         # Optional arguments are assumed to be either StaticInst flags
         # or an OpClass value.  To avoid having to import a complete
@@ -1144,6 +1126,18 @@ class InstObjParams(object):
                 error('InstObjParams: optional arg "%s" not recognized '
                       'as StaticInst::Flag or OpClass.' % oa)
 
+        # Make a basic guess on the operand class if not set.
+        # These are good enough for most cases.
+        if not self.op_class:
+            if 'IsStore' in self.flags:
+                self.op_class = 'MemWriteOp'
+            elif 'IsLoad' in self.flags or 'IsPrefetch' in self.flags:
+                self.op_class = 'MemReadOp'
+            elif 'IsFloating' in self.flags:
+                self.op_class = 'FloatAddOp'
+            else:
+                self.op_class = 'IntAluOp'
+
         # add flag initialization to contructor here to include
         # any flags added via opt_args
         self.constructor += makeFlagConstructor(self.flags)
@@ -1171,6 +1165,39 @@ class Stack(list):
     def top(self):
         return self[-1]
 
+# Format a file include stack backtrace as a string
+def backtrace(filename_stack):
+    fmt = "In file included from %s:"
+    return "\n".join([fmt % f for f in filename_stack])
+
+
+#######################
+#
+# LineTracker: track filenames along with line numbers in PLY lineno fields
+#     PLY explicitly doesn't do anything with 'lineno' except propagate
+#     it.  This class lets us tie filenames with the line numbers with a
+#     minimum of disruption to existing increment code.
+#
+
+class LineTracker(object):
+    def __init__(self, filename, lineno=1):
+        self.filename = filename
+        self.lineno = lineno
+
+    # Overload '+=' for increments.  We need to create a new object on
+    # each update else every token ends up referencing the same
+    # constantly incrementing instance.
+    def __iadd__(self, incr):
+        return LineTracker(self.filename, self.lineno + incr)
+
+    def __str__(self):
+        return "%s:%d" % (self.filename, self.lineno)
+
+    # In case there are places where someone really expects a number
+    def __int__(self):
+        return self.lineno
+
+
 #######################
 #
 # ISA Parser
@@ -1499,7 +1526,7 @@ class ISAParser(Grammar):
         try:
             t.value = int(t.value,0)
         except ValueError:
-            error(t, 'Integer value "%s" too large' % t.value)
+            error(t.lexer.lineno, 'Integer value "%s" too large' % t.value)
             t.value = 0
         return t
 
@@ -1528,13 +1555,13 @@ class ISAParser(Grammar):
         return t
 
     def t_NEWFILE(self, t):
-        r'^\#\#newfile\s+"[^"]*"'
-        self.fileNameStack.push((t.value[11:-1], t.lexer.lineno))
-        t.lexer.lineno = 0
+        r'^\#\#newfile\s+"[^"]*"\n'
+        self.fileNameStack.push(t.lexer.lineno)
+        t.lexer.lineno = LineTracker(t.value[11:-2])
 
     def t_ENDFILE(self, t):
-        r'^\#\#endfile'
-        (old_filename, t.lexer.lineno) = self.fileNameStack.pop()
+        r'^\#\#endfile\n'
+        t.lexer.lineno = self.fileNameStack.pop()
 
     #
     # The functions t_NEWLINE, t_ignore, and t_error are
@@ -1555,7 +1582,7 @@ class ISAParser(Grammar):
 
     # Error handler
     def t_error(self, t):
-        error(t, "illegal character '%s'" % t.value[0])
+        error(t.lexer.lineno, "illegal character '%s'" % t.value[0])
         t.skip(1)
 
     #####################################################################
@@ -1711,7 +1738,7 @@ del wrap
         except Exception, exc:
             if debug:
                 raise
-            error(t, 'error: %s in global let block "%s".' % (exc, t[2]))
+            error(t.lineno(1), 'In global let block: %s' % exc)
         GenCode(self,
                 header_output=self.exportContext["header_output"],
                 decoder_output=self.exportContext["decoder_output"],
@@ -1727,21 +1754,22 @@ del wrap
         except Exception, exc:
             if debug:
                 raise
-            error(t,
-                  'error: %s in def operand_types block "%s".' % (exc, t[3]))
+            error(t.lineno(1),
+                  'In def operand_types: %s' % exc)
 
     # Define the mapping from operand names to operand classes and
     # other traits.  Stored in operandNameMap.
     def p_def_operands(self, t):
         'def_operands : DEF OPERANDS CODELIT SEMI'
         if not hasattr(self, 'operandTypeMap'):
-            error(t, 'error: operand types must be defined before operands')
+            error(t.lineno(1),
+                  'error: operand types must be defined before operands')
         try:
             user_dict = eval('{' + t[3] + '}', self.exportContext)
         except Exception, exc:
             if debug:
                 raise
-            error(t, 'error: %s in def operands block "%s".' % (exc, t[3]))
+            error(t.lineno(1), 'In def operands: %s' % exc)
         self.buildOperandNameMap(user_dict, t.lexer.lineno)
 
     # A bitfield definition looks like:
@@ -1768,7 +1796,8 @@ del wrap
     def p_def_bitfield_struct(self, t):
         'def_bitfield_struct : DEF opt_signed BITFIELD ID id_with_dot SEMI'
         if (t[2] != ''):
-            error(t, 'error: structure bitfields are always unsigned.')
+            error(t.lineno(1),
+                  'error: structure bitfields are always unsigned.')
         expr = 'machInst.%s' % t[5]
         hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
         GenCode(self, header_output=hash_define).emit()
@@ -1922,7 +1951,7 @@ StaticInstPtr
     def p_decode_stmt_list_1(self, t):
         'decode_stmt_list : decode_stmt decode_stmt_list'
         if (t[1].has_decode_default and t[2].has_decode_default):
-            error(t, 'Two default cases in decode block')
+            error(t.lineno(1), 'Two default cases in decode block')
         t[0] = t[1] + t[2]
 
     #
@@ -1969,56 +1998,63 @@ StaticInstPtr
             self.formatStack.push(self.formatMap[t[1]])
             t[0] = ('', '// format %s' % t[1])
         except KeyError:
-            error(t, 'instruction format "%s" not defined.' % t[1])
+            error(t.lineno(1), 'instruction format "%s" not defined.' % t[1])
 
     # Nested decode block: if the value of the current field matches
-    # the specified constant, do a nested decode on some other field.
+    # the specified constant(s), do a nested decode on some other field.
     def p_decode_stmt_decode(self, t):
-        'decode_stmt : case_label COLON decode_block'
-        label = t[1]
+        'decode_stmt : case_list COLON decode_block'
+        case_list = t[1]
         codeObj = t[3]
         # just wrap the decoding code from the block as a case in the
         # outer switch statement.
-        codeObj.wrap_decode_block('\n%s:\n' % label)
-        codeObj.has_decode_default = (label == 'default')
+        codeObj.wrap_decode_block('\n%s\n' % ''.join(case_list))
+        codeObj.has_decode_default = (case_list == ['default:'])
         t[0] = codeObj
 
     # Instruction definition (finally!).
     def p_decode_stmt_inst(self, t):
-        'decode_stmt : case_label COLON inst SEMI'
-        label = t[1]
+        'decode_stmt : case_list COLON inst SEMI'
+        case_list = t[1]
         codeObj = t[3]
-        codeObj.wrap_decode_block('\n%s:' % label, 'break;\n')
-        codeObj.has_decode_default = (label == 'default')
+        codeObj.wrap_decode_block('\n%s' % ''.join(case_list), 'break;\n')
+        codeObj.has_decode_default = (case_list == ['default:'])
         t[0] = codeObj
 
-    # The case label is either a list of one or more constants or
-    # 'default'
-    def p_case_label_0(self, t):
-        'case_label : intlit_list'
-        def make_case(intlit):
-            if intlit >= 2**32:
-                return 'case ULL(%#x)' % intlit
-            else:
-                return 'case %#x' % intlit
-        t[0] = ': '.join(map(make_case, t[1]))
+    # The constant list for a decode case label must be non-empty, and must
+    # either be the keyword 'default', or made up of one or more
+    # comma-separated integer literals or strings which evaluate to
+    # constants when compiled as C++.
+    def p_case_list_0(self, t):
+        'case_list : DEFAULT'
+        t[0] = ['default:']
+
+    def prep_int_lit_case_label(self, lit):
+        if lit >= 2**32:
+            return 'case ULL(%#x): ' % lit
+        else:
+            return 'case %#x: ' % lit
 
-    def p_case_label_1(self, t):
-        'case_label : DEFAULT'
-        t[0] = 'default'
+    def prep_str_lit_case_label(self, lit):
+        return 'case %s: ' % lit
 
-    #
-    # The constant list for a decode case label must be non-empty, but
-    # may have one or more comma-separated integer literals in it.
-    #
-    def p_intlit_list_0(self, t):
-        'intlit_list : INTLIT'
-        t[0] = [t[1]]
+    def p_case_list_1(self, t):
+        'case_list : INTLIT'
+        t[0] = [self.prep_int_lit_case_label(t[1])]
+
+    def p_case_list_2(self, t):
+        'case_list : STRLIT'
+        t[0] = [self.prep_str_lit_case_label(t[1])]
+
+    def p_case_list_3(self, t):
+        'case_list : case_list COMMA INTLIT'
+        t[0] = t[1]
+        t[0].append(self.prep_int_lit_case_label(t[3]))
 
-    def p_intlit_list_1(self, t):
-        'intlit_list : intlit_list COMMA INTLIT'
+    def p_case_list_4(self, t):
+        'case_list : case_list COMMA STRLIT'
         t[0] = t[1]
-        t[0].append(t[3])
+        t[0].append(self.prep_str_lit_case_label(t[3]))
 
     # Define an instruction using the current instruction format
     # (specified by an enclosing format block).
@@ -2042,7 +2078,7 @@ StaticInstPtr
         try:
             format = self.formatMap[t[1]]
         except KeyError:
-            error(t, 'instruction format "%s" not defined.' % t[1])
+            error(t.lineno(1), 'instruction format "%s" not defined.' % t[1])
 
         codeObj = format.defineInst(self, t[3], t[5], t.lexer.lineno)
         comment = '\n// %s::%s(%s)\n' % (t[1], t[3], t[5])
@@ -2135,7 +2171,7 @@ StaticInstPtr
     # t.value)
     def p_error(self, t):
         if t:
-            error(t, "syntax error at '%s'" % t.value)
+            error(t.lexer.lineno, "syntax error at '%s'" % t.value)
         else:
             error("unknown syntax error")
 
@@ -2339,7 +2375,7 @@ StaticInstPtr
         except IOError:
             error('Error including file "%s"' % filename)
 
-        self.fileNameStack.push((filename, 0))
+        self.fileNameStack.push(LineTracker(filename))
 
         # Find any includes and include them
         def replace(matchobj):
@@ -2373,8 +2409,8 @@ StaticInstPtr
         # do this up front.
         isa_desc = self.read_and_flatten(isa_desc_file)
 
-        # Initialize filename stack with outer file.
-        self.fileNameStack.push((isa_desc_file, 0))
+        # Initialize lineno tracker
+        self.lex.lineno = LineTracker(isa_desc_file)
 
         # Parse.
         self.parse_string(isa_desc)
@@ -2385,7 +2421,10 @@ StaticInstPtr
         try:
             self._parse_isa_desc(*args, **kwargs)
         except ISAParserError, e:
-            e.exit(self.fileNameStack)
+            print backtrace(self.fileNameStack)
+            print "At %s:" % e.lineno
+            print e
+            sys.exit(1)
 
 # Called as script: get args from command line.
 # Args are: <isa desc file> <output dir>