Merge zizzer:/bk/newmem
[gem5.git] / src / arch / isa_parser.py
index b235398f18b2202cb9e11a645ce9602c2ae60aee..07ae72cb802c524b0441aebacbc819f9d3b30805 100755 (executable)
@@ -808,8 +808,7 @@ class GenCode:
 # a defineInst() method that generates the code for an instruction
 # definition.
 
-exportContextSymbols = ('InstObjParams', 'CodeBlock',
-                        'makeList', 're', 'string')
+exportContextSymbols = ('InstObjParams', 'makeList', 're', 'string')
 
 exportContext = {}
 
@@ -1003,27 +1002,80 @@ 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]')
+
 class Template:
     def __init__(self, t):
         self.template = t
 
     def subst(self, d):
+        myDict = None
+
+        # Protect non-Python-dict substitutions (e.g. if there's a printf
+        # in the templated C++ code)
+        template = protect_non_subst_percents(self.template)
+        # CPU-model-specific substitutions are handled later (in GenCode).
+        template = protect_cpu_symbols(template)
+
+        # Build a dict ('myDict') to use for the template substitution.
         # Start with the template namespace.  Make a copy since we're
         # going to modify it.
         myDict = templateMap.copy()
-        # if the argument is a dictionary, we just use it.
-        if isinstance(d, dict):
+
+        if isinstance(d, InstObjParams):
+            # If we're dealing with an InstObjParams object, we need
+            # to be a little more sophisticated.  The instruction-wide
+            # parameters are already formed, but the parameters which
+            # are only function wide still need to be generated.
+            compositeCode = ''
+
+            myDict.update(d.__dict__)
+            # The "operands" and "snippets" attributes of the InstObjParams
+            # objects are for internal use and not substitution.
+            del myDict['operands']
+            del myDict['snippets']
+
+            snippetLabels = [l for l in labelRE.findall(template)
+                             if d.snippets.has_key(l)]
+
+            snippets = dict([(s, mungeSnippet(d.snippets[s]))
+                             for s in snippetLabels])
+
+            myDict.update(snippets)
+
+            compositeCode = ' '.join(map(str, snippets.values()))
+
+            # Add in template itself in case it references any
+            # operands explicitly (like Mem)
+            compositeCode += ' ' + template
+
+            operands = SubOperandList(compositeCode, d.operands)
+
+            myDict['op_decl'] = operands.concatAttrStrings('op_decl')
+
+            is_src = lambda op: op.is_src
+            is_dest = lambda op: op.is_dest
+
+            myDict['op_src_decl'] = \
+                      operands.concatSomeAttrStrings(is_src, 'op_src_decl')
+            myDict['op_dest_decl'] = \
+                      operands.concatSomeAttrStrings(is_dest, 'op_dest_decl')
+
+            myDict['op_rd'] = operands.concatAttrStrings('op_rd')
+            myDict['op_wb'] = operands.concatAttrStrings('op_wb')
+
+            if d.operands.memOperand:
+                myDict['mem_acc_size'] = d.operands.memOperand.mem_acc_size
+                myDict['mem_acc_type'] = d.operands.memOperand.mem_acc_type
+
+        elif isinstance(d, dict):
+            # if the argument is a dictionary, we just use it.
             myDict.update(d)
-        # if the argument is an object, we use its attribute map.
         elif hasattr(d, '__dict__'):
+            # if the argument is an object, we use its attribute map.
             myDict.update(d.__dict__)
         else:
             raise TypeError, "Template.subst() arg must be or have dictionary"
-        # Protect non-Python-dict substitutions (e.g. if there's a printf
-        # in the templated C++ code)
-        template = protect_non_subst_percents(self.template)
-        # CPU-model-specific substitutions are handled later (in GenCode).
-        template = protect_cpu_symbols(template)
         return template % myDict
 
     # Convert to string.  This handles the case when a template with a
@@ -1180,15 +1232,16 @@ class IntRegOperand(Operand):
         if (self.ctype == 'float' or self.ctype == 'double'):
             error(0, 'Attempt to read integer register as FP')
         if (self.size == self.dflt_size):
-            return '%s = xc->readIntReg(this, %d);\n' % \
+            return '%s = xc->readIntRegOperand(this, %d);\n' % \
                    (self.base_name, self.src_reg_idx)
         elif (self.size > self.dflt_size):
-            int_reg_val = 'xc->readIntReg(this, %d)' % (self.src_reg_idx)
+            int_reg_val = 'xc->readIntRegOperand(this, %d)' % \
+                          (self.src_reg_idx)
             if (self.is_signed):
                 int_reg_val = 'sext<%d>(%s)' % (self.dflt_size, int_reg_val)
             return '%s = %s;\n' % (self.base_name, int_reg_val)
         else:
-            return '%s = bits(xc->readIntReg(this, %d), %d, 0);\n' % \
+            return '%s = bits(xc->readIntRegOperand(this, %d), %d, 0);\n' % \
                    (self.base_name, self.src_reg_idx, self.size-1)
 
     def makeWrite(self):
@@ -1201,7 +1254,7 @@ class IntRegOperand(Operand):
         wb = '''
         {
             %s final_val = %s;
-            xc->setIntReg(this, %d, final_val);\n
+            xc->setIntRegOperand(this, %d, final_val);\n
             if (traceData) { traceData->setData(final_val); }
         }''' % (self.dflt_ctype, final_val, self.dest_reg_idx)
         return wb
@@ -1227,13 +1280,13 @@ class FloatRegOperand(Operand):
         bit_select = 0
         width = 0;
         if (self.ctype == 'float'):
-            func = 'readFloatReg'
+            func = 'readFloatRegOperand'
             width = 32;
         elif (self.ctype == 'double'):
-            func = 'readFloatReg'
+            func = 'readFloatRegOperand'
             width = 64;
         else:
-            func = 'readFloatRegBits'
+            func = 'readFloatRegOperandBits'
             if (self.ctype == 'uint32_t'):
                 width = 32;
             elif (self.ctype == 'uint64_t'):
@@ -1259,18 +1312,18 @@ class FloatRegOperand(Operand):
         width = 0
         if (self.ctype == 'float'):
             width = 32
-            func = 'setFloatReg'
+            func = 'setFloatRegOperand'
         elif (self.ctype == 'double'):
             width = 64
-            func = 'setFloatReg'
+            func = 'setFloatRegOperand'
         elif (self.ctype == 'uint32_t'):
-            func = 'setFloatRegBits'
+            func = 'setFloatRegOperandBits'
             width = 32
         elif (self.ctype == 'uint64_t'):
-            func = 'setFloatRegBits'
+            func = 'setFloatRegOperandBits'
             width = 64
         else:
-            func = 'setFloatRegBits'
+            func = 'setFloatRegOperandBits'
             final_ctype = 'uint%d_t' % self.dflt_size
             if (self.size != self.dflt_size and self.is_signed):
                 final_val = 'sext<%d>(%s)' % (self.size, self.base_name)
@@ -1295,10 +1348,10 @@ class ControlRegOperand(Operand):
     def makeConstructor(self):
         c = ''
         if self.is_src:
-            c += '\n\t_srcRegIdx[%d] = %s;' % \
+            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;' % \
+            c += '\n\t_destRegIdx[%d] = %s + Ctrl_Base_DepTag;' % \
                  (self.dest_reg_idx, self.reg_spec)
         return c
 
@@ -1306,7 +1359,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->readMiscReg(%s)' % self.reg_spec
+        base = 'xc->readMiscRegOperandWithEffect(this, %s)' % self.src_reg_idx
         if self.size == self.dflt_size:
             return '%s = %s;\n' % (self.base_name, base)
         else:
@@ -1316,7 +1369,8 @@ 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->setMiscReg(%s, %s);\n' % (self.reg_spec, self.base_name)
+        wb = 'xc->setMiscRegOperandWithEffect(this, %s, %s);\n' % \
+             (self.dest_reg_idx, self.base_name)
         wb += 'if (traceData) { traceData->setData(%s); }' % \
               self.base_name
         return wb
@@ -1549,6 +1603,48 @@ class OperandList:
     def sort(self):
         self.items.sort(lambda a, b: a.sort_pri - b.sort_pri)
 
+class SubOperandList(OperandList):
+
+    # Find all the operands in the given code block.  Returns an operand
+    # descriptor list (instance of class OperandList).
+    def __init__(self, code, master_list):
+        self.items = []
+        self.bases = {}
+        # delete comments so we don't match on reg specifiers inside
+        code = commentRE.sub('', code)
+        # search for operands
+        next_pos = 0
+        while 1:
+            match = operandsRE.search(code, next_pos)
+            if not match:
+                # no more matches: we're done
+                break
+            op = match.groups()
+            # regexp groups are operand full name, base, and extension
+            (op_full, op_base, op_ext) = op
+            # find this op in the master list
+            op_desc = master_list.find_base(op_base)
+            if not op_desc:
+                error(0, 'Found operand %s which is not in the master list!' \
+                        ' This is an internal error' % \
+                          op_base)
+            else:
+                # See if we've already found this operand
+                op_desc = self.find_base(op_base)
+                if not op_desc:
+                    # if not, add a reference to it to this sub list
+                    self.append(master_list.bases[op_base])
+
+            # start next search after end of current match
+            next_pos = match.end()
+        self.sort()
+        self.memOperand = None
+        for op_desc in self.items:
+            if op_desc.isMem():
+                if self.memOperand:
+                    error(0, "Code block has more than one memory operand.")
+                self.memOperand = op_desc
+
 # Regular expression object to match C++ comments
 # (used in findOperands())
 commentRE = re.compile(r'//.*\n')
@@ -1563,8 +1659,12 @@ assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE)
 def substMungedOpNames(code):
     return operandsWithExtRE.sub(r'\1', code)
 
-def joinLists(t):
-    return map(string.join, t)
+# Fix up code snippets for final substitution in templates.
+def mungeSnippet(s):
+    if isinstance(s, str):
+        return substMungedOpNames(substBitOps(s))
+    else:
+        return s
 
 def makeFlagConstructor(flag_list):
     if len(flag_list) == 0:
@@ -1582,11 +1682,24 @@ def makeFlagConstructor(flag_list):
     code = pre + string.join(flag_list, post + pre) + post
     return code
 
-class CodeBlock:
-    def __init__(self, code):
-        self.orig_code = code
-        self.operands = OperandList(code)
-        self.code = substMungedOpNames(substBitOps(code))
+# Assume all instruction flags are of the form 'IsFoo'
+instFlagRE = re.compile(r'Is.*')
+
+# OpClass constants end in 'Op' except No_OpClass
+opClassRE = re.compile(r'.*Op|No_OpClass')
+
+class InstObjParams:
+    def __init__(self, mnem, class_name, base_class = '',
+                 snippets = {}, opt_args = []):
+        self.mnemonic = mnem
+        self.class_name = class_name
+        self.base_class = base_class
+        if not isinstance(snippets, dict):
+            snippets = {'code' : snippets}
+        compositeCode = ' '.join(map(str, snippets.values()))
+        self.snippets = snippets
+
+        self.operands = OperandList(compositeCode)
         self.constructor = self.operands.concatAttrStrings('constructor')
         self.constructor += \
                  '\n\t_numSrcRegs = %d;' % self.operands.numSrcRegs
@@ -1596,28 +1709,10 @@ class CodeBlock:
                  '\n\t_numFPDestRegs = %d;' % self.operands.numFPDestRegs
         self.constructor += \
                  '\n\t_numIntDestRegs = %d;' % self.operands.numIntDestRegs
-
-        self.op_decl = self.operands.concatAttrStrings('op_decl')
-
-        is_src = lambda op: op.is_src
-        is_dest = lambda op: op.is_dest
-
-        self.op_src_decl = \
-                  self.operands.concatSomeAttrStrings(is_src, 'op_src_decl')
-        self.op_dest_decl = \
-                  self.operands.concatSomeAttrStrings(is_dest, 'op_dest_decl')
-
-        self.op_rd = self.operands.concatAttrStrings('op_rd')
-        self.op_wb = self.operands.concatAttrStrings('op_wb')
-
         self.flags = self.operands.concatAttrLists('flags')
 
-        if self.operands.memOperand:
-            self.mem_acc_size = self.operands.memOperand.mem_acc_size
-            self.mem_acc_type = self.operands.memOperand.mem_acc_type
-
         # Make a basic guess on the operand class (function unit type).
-        # These are good enough for most cases, and will be overridden
+        # These are good enough for most cases, and can be overridden
         # later otherwise.
         if 'IsStore' in self.flags:
             self.op_class = 'MemWriteOp'
@@ -1628,48 +1723,6 @@ class CodeBlock:
         else:
             self.op_class = 'IntAluOp'
 
-# Assume all instruction flags are of the form 'IsFoo'
-instFlagRE = re.compile(r'Is.*')
-
-# OpClass constants end in 'Op' except No_OpClass
-opClassRE = re.compile(r'.*Op|No_OpClass')
-
-class InstObjParams:
-    def __init__(self, mnem, class_name, base_class = '',
-                 code = None, opt_args = [], extras = {}):
-        self.mnemonic = mnem
-        self.class_name = class_name
-        self.base_class = base_class
-        if code:
-            #If the user already made a CodeBlock, pick the parts from it
-            if isinstance(code, CodeBlock):
-                origCode = code.orig_code
-                codeBlock = code
-            else:
-                origCode = code
-                codeBlock = CodeBlock(code)
-            stringExtras = {}
-            otherExtras = {}
-            for (k, v) in extras.items():
-                if type(v) == str:
-                    stringExtras[k] = v
-                else:
-                    otherExtras[k] = v
-            compositeCode = "\n".join([origCode] + stringExtras.values())
-            # compositeCode = '\n'.join([origCode] +
-            #      [pair[1] for pair in extras])
-            compositeBlock = CodeBlock(compositeCode)
-            for code_attr in compositeBlock.__dict__.keys():
-                setattr(self, code_attr, getattr(compositeBlock, code_attr))
-            for (key, snippet) in stringExtras.items():
-                setattr(self, key, CodeBlock(snippet).code)
-            for (key, item) in otherExtras.items():
-                setattr(self, key, item)
-            self.code = codeBlock.code
-            self.orig_code = origCode
-        else:
-            self.constructor = ''
-            self.flags = []
         # Optional arguments are assumed to be either StaticInst flags
         # or an OpClass value.  To avoid having to import a complete
         # list of these values to match against, we do it ad-hoc