arm: add ARM support to M5
[gem5.git] / src / arch / isa_parser.py
index 9b63c88428e76e65e9dcd309d3a5425f682a1e3a..bbdd95bb00fe76b5f3179cc4be6be38321290b7a 100755 (executable)
@@ -40,8 +40,8 @@ from types import *
 # of 'build' in the current tree.
 sys.path[0:0] = [os.environ['M5_PLY']]
 
-import lex
-import yacc
+from ply import lex
+from ply import yacc
 
 #####################################################################
 #
@@ -81,12 +81,12 @@ tokens = reserved + (
     # code literal
     'CODELIT',
 
-    # ( ) [ ] { } < > , ; : :: *
+    # ( ) [ ] { } < > , ; : :: *
     'LPAREN', 'RPAREN',
     'LBRACKET', 'RBRACKET',
     'LBRACE', 'RBRACE',
     'LESS', 'GREATER', 'EQUALS',
-    'COMMA', 'SEMI', 'COLON', 'DBLCOLON',
+    'COMMA', 'SEMI', 'DOT', 'COLON', 'DBLCOLON',
     'ASTERISK',
 
     # C preprocessor directives
@@ -113,6 +113,7 @@ t_GREATER          = r'\>'
 t_EQUALS           = r'='
 t_COMMA            = r','
 t_SEMI             = r';'
+t_DOT              = r'\.'
 t_COLON            = r':'
 t_DBLCOLON         = r'::'
 t_ASTERISK        = r'\*'
@@ -133,7 +134,7 @@ def t_INTLIT(t):
     try:
         t.value = int(t.value,0)
     except ValueError:
-        error(t.lineno, 'Integer value "%s" too large' % t.value)
+        error(t.lexer.lineno, 'Integer value "%s" too large' % t.value)
         t.value = 0
     return t
 
@@ -143,7 +144,7 @@ def t_STRLIT(t):
     r"(?m)'([^'])+'"
     # strip off quotes
     t.value = t.value[1:-1]
-    t.lineno += t.value.count('\n')
+    t.lexer.lineno += t.value.count('\n')
     return t
 
 
@@ -153,22 +154,22 @@ def t_CODELIT(t):
     r"(?m)\{\{([^\}]|}(?!\}))+\}\}"
     # strip off {{ & }}
     t.value = t.value[2:-2]
-    t.lineno += t.value.count('\n')
+    t.lexer.lineno += t.value.count('\n')
     return t
 
 def t_CPPDIRECTIVE(t):
     r'^\#[^\#].*\n'
-    t.lineno += t.value.count('\n')
+    t.lexer.lineno += t.value.count('\n')
     return t
 
 def t_NEWFILE(t):
     r'^\#\#newfile\s+"[\w/.-]*"'
-    fileNameStack.push((t.value[11:-1], t.lineno))
-    t.lineno = 0
+    fileNameStack.push((t.value[11:-1], t.lexer.lineno))
+    t.lexer.lineno = 0
 
 def t_ENDFILE(t):
     r'^\#\#endfile'
-    (old_filename, t.lineno) = fileNameStack.pop()
+    (old_filename, t.lexer.lineno) = fileNameStack.pop()
 
 #
 # The functions t_NEWLINE, t_ignore, and t_error are
@@ -178,7 +179,7 @@ def t_ENDFILE(t):
 # Newlines
 def t_NEWLINE(t):
     r'\n+'
-    t.lineno += t.value.count('\n')
+    t.lexer.lineno += t.value.count('\n')
 
 # Comments
 def t_comment(t):
@@ -189,11 +190,11 @@ t_ignore           = ' \t\x0c'
 
 # Error handler
 def t_error(t):
-    error(t.lineno, "illegal character '%s'" % t.value[0])
+    error(t.lexer.lineno, "illegal character '%s'" % t.value[0])
     t.skip(1)
 
 # Build the lexer
-lex.lex()
+lexer = lex.lex()
 
 #####################################################################
 #
@@ -261,6 +262,7 @@ def p_defs_and_outputs_1(t):
 def p_def_or_output(t):
     '''def_or_output : def_format
                      | def_bitfield
+                     | def_bitfield_struct
                      | def_template
                      | def_operand_types
                      | def_operands
@@ -309,12 +311,19 @@ def p_output_exec(t):
 def p_global_let(t):
     'global_let : LET CODELIT SEMI'
     updateExportContext()
+    exportContext["header_output"] = ''
+    exportContext["decoder_output"] = ''
+    exportContext["exec_output"] = ''
+    exportContext["decode_block"] = ''
     try:
         exec fixPythonIndentation(t[2]) in exportContext
     except Exception, exc:
-        error(t.lineno(1),
+        error(t.lexer.lineno,
               'error: %s in global let block "%s".' % (exc, t[2]))
-    t[0] = GenCode() # contributes nothing to the output C++ file
+    t[0] = GenCode(header_output = exportContext["header_output"],
+                   decoder_output = exportContext["decoder_output"],
+                   exec_output = exportContext["exec_output"],
+                   decode_block = exportContext["decode_block"])
 
 # Define the mapping from operand type extensions to C++ types and bit
 # widths (stored in operandTypeMap).
@@ -323,9 +332,9 @@ def p_def_operand_types(t):
     try:
         userDict = eval('{' + t[3] + '}')
     except Exception, exc:
-        error(t.lineno(1),
+        error(t.lexer.lineno,
               'error: %s in def operand_types block "%s".' % (exc, t[3]))
-    buildOperandTypeMap(userDict, t.lineno(1))
+    buildOperandTypeMap(userDict, t.lexer.lineno)
     t[0] = GenCode() # contributes nothing to the output C++ file
 
 # Define the mapping from operand names to operand classes and other
@@ -333,14 +342,14 @@ def p_def_operand_types(t):
 def p_def_operands(t):
     'def_operands : DEF OPERANDS CODELIT SEMI'
     if not globals().has_key('operandTypeMap'):
-        error(t.lineno(1),
+        error(t.lexer.lineno,
               'error: operand types must be defined before operands')
     try:
         userDict = eval('{' + t[3] + '}')
     except Exception, exc:
-        error(t.lineno(1),
+        error(t.lexer.lineno,
               'error: %s in def operands block "%s".' % (exc, t[3]))
-    buildOperandNameMap(userDict, t.lineno(1))
+    buildOperandNameMap(userDict, t.lexer.lineno)
     t[0] = GenCode() # contributes nothing to the output C++ file
 
 # A bitfield definition looks like:
@@ -363,6 +372,23 @@ def p_def_bitfield_1(t):
     hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
     t[0] = GenCode(header_output = hash_define)
 
+# alternate form for structure member: 'def bitfield <ID> <ID>'
+def p_def_bitfield_struct(t):
+    'def_bitfield_struct : DEF opt_signed BITFIELD ID id_with_dot SEMI'
+    if (t[2] != ''):
+        error(t.lexer.lineno, '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)
+    t[0] = GenCode(header_output = hash_define)
+
+def p_id_with_dot_0(t):
+    'id_with_dot : ID'
+    t[0] = t[1]
+
+def p_id_with_dot_1(t):
+    'id_with_dot : ID DOT id_with_dot'
+    t[0] = t[1] + t[2] + t[3]
+
 def p_opt_signed_0(t):
     'opt_signed : SIGNED'
     t[0] = t[1]
@@ -384,7 +410,7 @@ def p_def_template(t):
 def p_def_format(t):
     'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI'
     (id, params, code) = (t[3], t[5], t[7])
-    defFormat(id, params, code, t.lineno(1))
+    defFormat(id, params, code, t.lexer.lineno)
     t[0] = GenCode()
 
 # The formal parameter list for an instruction format is a possibly
@@ -494,7 +520,7 @@ def p_decode_stmt_list_0(t):
 def p_decode_stmt_list_1(t):
     'decode_stmt_list : decode_stmt decode_stmt_list'
     if (t[1].has_decode_default and t[2].has_decode_default):
-        error(t.lineno(1), 'Two default cases in decode block')
+        error(t.lexer.lineno, 'Two default cases in decode block')
     t[0] = t[1] + t[2]
 
 #
@@ -539,7 +565,7 @@ def p_push_format_id(t):
         formatStack.push(formatMap[t[1]])
         t[0] = ('', '// format %s' % t[1])
     except KeyError:
-        error(t.lineno(1), 'instruction format "%s" not defined.' % t[1])
+        error(t.lexer.lineno, '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.
@@ -591,7 +617,7 @@ def p_inst_0(t):
     'inst : ID LPAREN arg_list RPAREN'
     # Pass the ID and arg list to the current format class to deal with.
     currentFormat = formatStack.top()
-    codeObj = currentFormat.defineInst(t[1], t[3], t.lineno(1))
+    codeObj = currentFormat.defineInst(t[1], t[3], t.lexer.lineno)
     args = ','.join(map(str, t[3]))
     args = re.sub('(?m)^', '//', args)
     args = re.sub('^//', '', args)
@@ -606,8 +632,8 @@ def p_inst_1(t):
     try:
         format = formatMap[t[1]]
     except KeyError:
-        error(t.lineno(1), 'instruction format "%s" not defined.' % t[1])
-    codeObj = format.defineInst(t[3], t[5], t.lineno(1))
+        error(t.lexer.lineno, 'instruction format "%s" not defined.' % t[1])
+    codeObj = format.defineInst(t[3], t[5], t.lexer.lineno)
     comment = '\n// %s::%s(%s)\n' % (t[1], t[3], t[5])
     codeObj.prepend_all(comment)
     t[0] = codeObj
@@ -696,14 +722,14 @@ def p_empty(t):
 # *token*, not a grammar symbol (hence the need to use t.value)
 def p_error(t):
     if t:
-        error(t.lineno, "syntax error at '%s'" % t.value)
+        error(t.lexer.lineno, "syntax error at '%s'" % t.value)
     else:
         error(0, "unknown syntax error", True)
 
 # END OF GRAMMAR RULES
 #
 # Now build the parser.
-yacc.yacc()
+parser = yacc.yacc()
 
 
 #####################################################################
@@ -840,7 +866,11 @@ class Format:
         context = {}
         updateExportContext()
         context.update(exportContext)
-        context.update({ 'name': name, 'Name': string.capitalize(name) })
+        if len(name):
+            Name = name[0].upper()
+            if len(name) > 1:
+                Name += name[1:]
+        context.update({ 'name': name, 'Name': Name })
         try:
             vars = self.func(self.user_code, context, *args[0], **args[1])
         except Exception, exc:
@@ -1002,7 +1032,7 @@ def substBitOps(code):
 # Template objects are format strings that allow substitution from
 # the attribute spaces of other objects (e.g. InstObjParams instances).
 
-labelRE = re.compile(r'[^%]%\(([^\)]+)\)[sd]')
+labelRE = re.compile(r'(?<!%)%\(([^\)]+)\)[sd]')
 
 class Template:
     def __init__(self, t):
@@ -1205,6 +1235,9 @@ class Operand(object):
     def isControlReg(self):
         return 0
 
+    def isIControlReg(self):
+        return 0
+
     def getFlags(self):
         # note the empty slice '[:]' gives us a copy of self.flags[0]
         # instead of a reference to it
@@ -1368,7 +1401,7 @@ class ControlRegOperand(Operand):
         bit_select = 0
         if (self.ctype == 'float' or self.ctype == 'double'):
             error(0, 'Attempt to read control register as FP')
-        base = 'xc->readMiscRegOperandWithEffect(this, %s)' % self.src_reg_idx
+        base = 'xc->readMiscRegOperand(this, %s)' % self.src_reg_idx
         if self.size == self.dflt_size:
             return '%s = %s;\n' % (self.base_name, base)
         else:
@@ -1378,12 +1411,71 @@ class ControlRegOperand(Operand):
     def makeWrite(self):
         if (self.ctype == 'float' or self.ctype == 'double'):
             error(0, 'Attempt to write control register as FP')
-        wb = 'xc->setMiscRegOperandWithEffect(this, %s, %s);\n' % \
+        wb = 'xc->setMiscRegOperand(this, %s, %s);\n' % \
              (self.dest_reg_idx, self.base_name)
         wb += 'if (traceData) { traceData->setData(%s); }' % \
               self.base_name
         return wb
 
+class IControlRegOperand(Operand):
+    def isReg(self):
+        return 1
+
+    def isIControlReg(self):
+        return 1
+
+    def makeConstructor(self):
+        c = ''
+        if self.is_src:
+            c += '\n\t_srcRegIdx[%d] = %s + Ctrl_Base_DepTag;' % \
+                 (self.src_reg_idx, self.reg_spec)
+        if self.is_dest:
+            c += '\n\t_destRegIdx[%d] = %s + Ctrl_Base_DepTag;' % \
+                 (self.dest_reg_idx, self.reg_spec)
+        return c
+
+    def makeRead(self):
+        bit_select = 0
+        if (self.ctype == 'float' or self.ctype == 'double'):
+            error(0, 'Attempt to read control register as FP')
+        base = 'xc->readMiscReg(%s)' % self.reg_spec
+        if self.size == self.dflt_size:
+            return '%s = %s;\n' % (self.base_name, base)
+        else:
+            return '%s = bits(%s, %d, 0);\n' % \
+                   (self.base_name, base, self.size-1)
+
+    def makeWrite(self):
+        if (self.ctype == 'float' or self.ctype == 'double'):
+            error(0, 'Attempt to write control register as FP')
+        wb = 'xc->setMiscReg(%s, %s);\n' % \
+             (self.reg_spec, self.base_name)
+        wb += 'if (traceData) { traceData->setData(%s); }' % \
+              self.base_name
+        return wb
+
+class ControlBitfieldOperand(ControlRegOperand):
+    def makeRead(self):
+        bit_select = 0
+        if (self.ctype == 'float' or self.ctype == 'double'):
+            error(0, 'Attempt to read control register as FP')
+        base = 'xc->readMiscReg(%s)' % self.reg_spec
+        name = self.base_name
+        return '%s = bits(%s, %s_HI, %s_LO);' % \
+               (name, base, name, name)
+
+    def makeWrite(self):
+        if (self.ctype == 'float' or self.ctype == 'double'):
+            error(0, 'Attempt to write control register as FP')
+        base = 'xc->readMiscReg(%s)' % self.reg_spec
+        name = self.base_name
+        wb_val = 'insertBits(%s, %s_HI, %s_LO, %s)' % \
+                    (base, name, name, self.base_name)
+        wb = 'xc->setMiscRegOperand(this, %s, %s );\n' % (self.dest_reg_idx, wb_val)
+        wb += 'if (traceData) { traceData->setData(%s); }' % \
+              self.base_name
+        return wb
+
 class MemOperand(Operand):
     def isMem(self):
         return 1
@@ -1412,6 +1504,25 @@ class MemOperand(Operand):
     def makeAccSize(self):
         return self.size
 
+class UPCOperand(Operand):
+    def makeConstructor(self):
+        return ''
+
+    def makeRead(self):
+        return '%s = xc->readMicroPC();\n' % self.base_name
+
+    def makeWrite(self):
+        return 'xc->setMicroPC(%s);\n' % self.base_name
+
+class NUPCOperand(Operand):
+    def makeConstructor(self):
+        return ''
+
+    def makeRead(self):
+        return '%s = xc->readNextMicroPC();\n' % self.base_name
+
+    def makeWrite(self):
+        return 'xc->setNextMicroPC(%s);\n' % self.base_name
 
 class NPCOperand(Operand):
     def makeConstructor(self):
@@ -1502,6 +1613,8 @@ def buildOperandNameMap(userDict, lineno):
     global operandsWithExtRE
     operandsWithExtRE = re.compile(operandsWithExtREString, re.MULTILINE)
 
+maxInstSrcRegs = 0
+maxInstDestRegs = 0
 
 class OperandList:
 
@@ -1565,6 +1678,12 @@ class OperandList:
                 if self.memOperand:
                     error(0, "Code block has more than one memory operand.")
                 self.memOperand = op_desc
+        global maxInstSrcRegs
+        global maxInstDestRegs
+        if maxInstSrcRegs < self.numSrcRegs:
+            maxInstSrcRegs = self.numSrcRegs
+        if maxInstDestRegs < self.numDestRegs:
+            maxInstDestRegs = self.numDestRegs
         # now make a final pass to finalize op_desc fields that may depend
         # on the register enumeration
         for op_desc in self.items:
@@ -1784,6 +1903,22 @@ namespace %(namespace)s {
 %(decode_function)s
 '''
 
+max_inst_regs_template = '''
+/*
+ * DO NOT EDIT THIS FILE!!!
+ *
+ * It was automatically generated from the ISA description in %(filename)s
+ */
+
+namespace %(namespace)s {
+
+    const int MaxInstSrcRegs = %(MaxInstSrcRegs)d;
+    const int MaxInstDestRegs = %(MaxInstDestRegs)d;
+
+} // namespace %(namespace)s
+
+'''
+
 
 # Update the output file only if the new contents are different from
 # the current contents.  Minimizes the files that need to be rebuilt
@@ -1851,7 +1986,8 @@ def parse_isa_desc(isa_desc_file, output_dir):
     fileNameStack.push((isa_desc_file, 0))
 
     # Parse it.
-    (isa_name, namespace, global_code, namespace_code) = yacc.parse(isa_desc)
+    (isa_name, namespace, global_code, namespace_code) = \
+        parser.parse(isa_desc, lexer=lexer)
 
     # grab the last three path components of isa_desc_file to put in
     # the output
@@ -1882,6 +2018,16 @@ def parse_isa_desc(isa_desc_file, output_dir):
         update_if_needed(output_dir + '/' + cpu.filename,
                           file_template % vars())
 
+    # The variable names here are hacky, but this will creat local variables
+    # which will be referenced in vars() which have the value of the globals.
+    global maxInstSrcRegs
+    MaxInstSrcRegs = maxInstSrcRegs
+    global maxInstDestRegs
+    MaxInstDestRegs = maxInstDestRegs
+    # max_inst_regs.hh
+    update_if_needed(output_dir + '/max_inst_regs.hh', \
+            max_inst_regs_template % vars())
+
 # global list of CpuModel objects (see cpu_models.py)
 cpu_models = []