X86: Take advantage of new PCState syntax.
[gem5.git] / src / arch / x86 / isa / specialize.isa
index de77f130bf2b0b8697017d02f3932393088a4712..779abefc7f59db329869b2b5119b29056c166197 100644 (file)
@@ -3,43 +3,25 @@
 // Copyright (c) 2007 The Hewlett-Packard Development Company
 // All rights reserved.
 //
-// Redistribution and use of this software in source and binary forms,
-// with or without modification, are permitted provided that the
-// following conditions are met:
+// 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.
 //
-// The software must be used only for Non-Commercial Use which means any
-// use which is NOT directed to receiving any direct monetary
-// compensation for, or commercial advantage from such use.  Illustrative
-// examples of non-commercial use are academic research, personal study,
-// teaching, education and corporate research & development.
-// Illustrative examples of commercial use are distributing products for
-// commercial advantage and providing services using the software for
-// commercial advantage.
-//
-// If you wish to use this software or functionality therein that may be
-// covered by patents for commercial use, please contact:
-//     Director of Intellectual Property Licensing
-//     Office of Strategy and Technology
-//     Hewlett-Packard Company
-//     1501 Page Mill Road
-//     Palo Alto, California  94304
-//
-// Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.  Redistributions
-// in binary form must reproduce the above copyright notice, this list of
-// conditions and the following disclaimer in the documentation and/or
-// other materials provided with the distribution.  Neither the name of
-// the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
 // contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.  No right of
-// sublicense is granted herewith.  Derivatives of the software and
-// output created using the software may be prepared, but only for
-// Non-Commercial Uses.  Derivatives of the software may be shared with
-// others provided: (i) the others agree to abide by the list of
-// conditions herein which includes the Non-Commercial Use restrictions;
-// and (ii) such Derivatives of the software include the above copyright
-// notice to acknowledge the contribution from this software where
-// applicable, this list of conditions and the disclaimer below.
+// this software without specific prior written permission.
 //
 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 let {{
     # This code builds up a decode block which decodes based on switchval.
     # vals is a dict which matches case values with what should be decoded to.
-    # builder is called on the exploded contents of "vals" values to generate
-    # whatever code should be used.
-    def doSplitDecode(Name, builder, switchVal, vals, default = None):
-        decode_block = 'switch(%s) {\n' % switchVal
+    # Each element of the dict is a list containing a function and then the
+    # arguments to pass to it.
+    def doSplitDecode(switchVal, vals, default = None):
+        blocks = OutputBlocks()
+        blocks.decode_block = 'switch(%s) {\n' % switchVal
         for (val, todo) in vals.items():
-            new_block = builder(Name, *todo)
-            new_block = '\tcase %s: %s\n' % (val, new_block)
-            decode_block += new_block
+            new_blocks = todo[0](*todo[1:])
+            new_blocks.decode_block = \
+                '\tcase %s: %s\n' % (val, new_blocks.decode_block)
+            blocks.append(new_blocks)
         if default:
-            new_block = builder(Name, *default)
-            new_block = '\tdefault: %s\n' % new_block
-            decode_block += new_block
-        decode_block += '}\n'
-        return decode_block
+            new_blocks = default[0](*default[1:])
+            new_blocks.decode_block = \
+                '\tdefault: %s\n' % new_blocks.decode_block
+            blocks.append(new_blocks)
+        blocks.decode_block += '}\n'
+        return blocks
+}};
+
+let {{
+    def doRipRelativeDecode(Name, opTypes, env):
+        # print "RIPing %s with opTypes %s" % (Name, opTypes)
+        env.memoryInst = True
+        normEnv = copy.copy(env)
+        normEnv.addToDisassembly(
+                '''printMem(out, env.seg, env.scale, env.index, env.base,
+                    machInst.displacement, env.addressSize, false);''')
+        normBlocks = specializeInst(Name + "_M", copy.copy(opTypes), normEnv)
+        ripEnv = copy.copy(env)
+        ripEnv.addToDisassembly(
+                '''printMem(out, env.seg, 1, 0, 0,
+                    machInst.displacement, env.addressSize, true);''')
+        ripBlocks = specializeInst(Name + "_P", copy.copy(opTypes), ripEnv)
+
+        blocks = OutputBlocks()
+        blocks.append(normBlocks)
+        blocks.append(ripBlocks)
+
+        blocks.decode_block = '''
+        if(machInst.modRM.mod == 0 &&
+          machInst.modRM.rm == 5 &&
+          machInst.mode.submode == SixtyFourBitMode)
+        { %s }
+        else
+        { %s }''' % \
+         (ripBlocks.decode_block, normBlocks.decode_block)
+        return blocks
 }};
 
 let {{
     class OpType(object):
-        parser = re.compile(r"(?P<tag>[A-Z][A-Z]*)(?P<size>[a-z][a-z]*)|(r(?P<reg>[A-Z0-9])(?P<rsize>[a-z]*))")
+        parser = re.compile(r"(?P<tag>[A-Z]+)(?P<size>[a-z]*)|(r(?P<reg>[A-Z0-9]+)(?P<rsize>[a-z]*))")
         def __init__(self, opTypeString):
             match = OpType.parser.search(opTypeString)
             if match == None:
@@ -90,72 +105,137 @@ let {{
             self.reg = match.group("reg")
             self.tag = match.group("tag")
             self.size = match.group("size")
-            self.rsize = match.group("rsize")
+            if not self.size:
+                self.size = match.group("rsize")
+
+    ModRMRegIndex = "(MODRM_REG | (REX_R << 3))"
+    ModRMRMIndex = "(MODRM_RM | (REX_B << 3))"
+    InstRegIndex = "(OPCODE_OP_BOTTOM3 | (REX_B << 3))"
 
     # This function specializes the given piece of code to use a particular
     # set of argument types described by "opTypes".
     def specializeInst(Name, opTypes, env):
+        # print "Specializing %s with opTypes %s" % (Name, opTypes)
         while len(opTypes):
-            # print "Building a composite op with tags", opTypes
-            # print "And code", code
-            opNum = len(opTypes) - 1
-
             # Parse the operand type string we're working with
-            opType = OpType(opTypes[opNum])
+            opType = OpType(opTypes[0])
+            opTypes.pop(0)
+
+            if opType.tag not in ("I", "J", "P", "PR", "Q", "V", "VR", "W"):
+                if opType.size:
+                    env.setSize(opType.size)
 
             if opType.reg:
                 #Figure out what to do with fixed register operands
                 #This is the index to use, so we should stick it some place.
-                print "INTREG_R%s" % (opType.reg + opType.size.upper())
-                if opType.size:
-                    if opType.rsize in ("l", "h", "b"):
-                        print "byte"
-                    elif opType.rsize == "x":
-                        print "word"
-                    else:
-                        print "Didn't recognize fixed register size %s!" % opType.rsize
+                if opType.reg in ("A", "B", "C", "D"):
+                    regString = "INTREG_R%sX" % opType.reg
+                else:
+                    regString = "INTREG_R%s" % opType.reg
+                env.addReg(regString)
+                env.addToDisassembly(
+                        "printReg(out, %s, regSize);\n" % regString)
+                Name += "_R"
+            elif opType.tag == "B":
+                # This refers to registers whose index is encoded as part of the opcode
+                env.addToDisassembly(
+                        "printReg(out, %s, regSize);\n" % InstRegIndex)
+                Name += "_R"
+                env.addReg(InstRegIndex)
+            elif opType.tag == "M":
+                # This refers to memory. The macroop constructor sets up modrm
+                # addressing. Non memory modrm settings should cause an error.
+                env.doModRM = True
+                return doRipRelativeDecode(Name, opTypes, env)
             elif opType.tag == None or opType.size == None:
                 raise Exception, "Problem parsing operand tag: %s" % opType.tag
-            elif opType.tag in ("C", "D", "G", "P", "S", "T", "V"):
+            elif opType.tag == "C":
+                # A control register indexed by the "reg" field
+                env.addReg(ModRMRegIndex)
+                env.addToDisassembly(
+                        "ccprintf(out, \"CR%%d\", %s);\n" % ModRMRegIndex)
+                Name += "_C"
+            elif opType.tag == "D":
+                # A debug register indexed by the "reg" field
+                env.addReg(ModRMRegIndex)
+                env.addToDisassembly(
+                        "ccprintf(out, \"DR%%d\", %s);\n" % ModRMRegIndex)
+                Name += "_D"
+            elif opType.tag == "S":
+                # A segment selector register indexed by the "reg" field
+                env.addReg(ModRMRegIndex)
+                env.addToDisassembly(
+                        "printSegment(out, %s);\n" % ModRMRegIndex)
+                Name += "_S"
+            elif opType.tag in ("G", "P", "T", "V"):
                 # Use the "reg" field of the ModRM byte to select the register
-                print "(uint8_t)MODRM_REG"
+                env.addReg(ModRMRegIndex)
+                env.addToDisassembly(
+                        "printReg(out, %s, regSize);\n" % ModRMRegIndex)
+                if opType.tag == "P":
+                    Name += "_MMX"
+                elif opType.tag == "V":
+                    Name += "_XMM"
+                else:
+                    Name += "_R"
             elif opType.tag in ("E", "Q", "W"):
                 # This might refer to memory or to a register. We need to
                 # divide it up farther.
-                print "(uint8_t)MODRM_RM"
-                regTypes = copy.copy(opTypes)
-                regTypes.pop(0)
                 regEnv = copy.copy(env)
-                # This needs to refer to memory, but we'll fill in the details
-                # later. It needs to take into account unaligned memory
-                # addresses.
-                # code = "GenFault #${new UnimpInstFault}#\n" + code
-                print "%0"
-                memTypes = copy.copy(opTypes)
-                memTypes.pop(0)
+                regEnv.addReg(ModRMRMIndex)
+                regEnv.addToDisassembly(
+                        "printReg(out, %s, regSize);\n" % ModRMRMIndex)
+                # This refers to memory. The macroop constructor should set up
+                # modrm addressing.
                 memEnv = copy.copy(env)
-                return doSplitDecode(Name, specializeInst, "MODRM_MOD",
-                    {"3" : (regTypes, memEnv)}, (memTypes, memEnv))
+                memEnv.doModRM = True
+                regSuffix = "_R"
+                if opType.tag == "Q":
+                    regSuffix = "_MMX"
+                elif opType.tag == "W":
+                    regSuffix = "_XMM"
+                return doSplitDecode("MODRM_MOD",
+                    {"3" : (specializeInst, Name + regSuffix,
+                            copy.copy(opTypes), regEnv)},
+                           (doRipRelativeDecode, Name,
+                            copy.copy(opTypes), memEnv))
             elif opType.tag in ("I", "J"):
-                # Immediates are already in the instruction, so don't leave in
-                # those parameters
-                print "IMMEDIATE"
-            elif opType.tag == "M":
-                # This needs to refer to memory, but we'll fill in the details
-                # later. It needs to take into account unaligned memory
-                # addresses.
-                #code = "GenFault #${new UnimpInstFault}#\n" + code
-                print "%0"
+                # Immediates
+                env.addToDisassembly(
+                        "ccprintf(out, \"%#x\", machInst.immediate);\n")
+                Name += "_I"
+            elif opType.tag == "O":
+                # Immediate containing a memory offset
+                Name += "_MI"
             elif opType.tag in ("PR", "R", "VR"):
-                # There should probably be a check here to verify that mod
-                # is equal to 11b
-                print "(uint8_t)MODRM_RM"
+                # Non register modrm settings should cause an error
+                env.addReg(ModRMRMIndex)
+                env.addToDisassembly(
+                        "printReg(out, %s, regSize);\n" % ModRMRMIndex)
+                if opType.tag == "PR":
+                    Name += "_MMX"
+                elif opType.tag == "VR":
+                    Name += "_XMM"
+                else:
+                    Name += "_R"
+            elif opType.tag in ("X", "Y"):
+                # This type of memory addressing is for string instructions.
+                # They'll use the right index and segment internally.
+                if opType.tag == "X":
+                    env.addToDisassembly(
+                            '''printMem(out, env.seg,
+                                1, X86ISA::ZeroReg, X86ISA::INTREG_RSI, 0,
+                                env.addressSize, false);''')
+                else:
+                    env.addToDisassembly(
+                            '''printMem(out, SEGMENT_REG_ES,
+                                1, X86ISA::ZeroReg, X86ISA::INTREG_RDI, 0,
+                                env.addressSize, false);''')
+                Name += "_M"
             else:
                 raise Exception, "Unrecognized tag %s." % opType.tag
-            opTypes.pop(0)
 
-        # At this point, we've built up "code" to have all the necessary extra
-        # instructions needed to implement whatever types of operands were
-        # specified. Now we'll assemble it it into a StaticInst.
+        # Generate code to return a macroop of the given name which will
+        # operate in the "emulation environment" env
         return genMacroop(Name, env)
 }};