Merge with the main repository again.
[gem5.git] / src / arch / x86 / predecoder.cc
index 5c98a1831664d183f1fd6919849ac5eac21ce2c6..a4aa93b4817a79306e091e12ccbc196e4502b828 100644 (file)
@@ -1,44 +1,26 @@
 /*
- * Copyright (c) 2007 The Hewlett-Packard Development Company
+ * Copyright (c) 2007-2008 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
  * Authors: Gabe Black
  */
 
+#include "arch/x86/regs/misc.hh"
 #include "arch/x86/predecoder.hh"
 #include "base/misc.hh"
 #include "base/trace.hh"
-#include "sim/host.hh"
+#include "base/types.hh"
+#include "cpu/thread_context.hh"
+#include "debug/Predecoder.hh"
 
 namespace X86ISA
 {
-    void Predecoder::reset()
+    void Predecoder::doReset()
     {
         origPC = basePC + offset;
         DPRINTF(Predecoder, "Setting origPC to %#x\n", origPC);
         emi.rex = 0;
         emi.legacy = 0;
         emi.opcode.num = 0;
+        emi.opcode.op = 0;
+        emi.opcode.prefixA = emi.opcode.prefixB = 0;
 
         immediateCollected = 0;
         emi.immediate = 0;
-        displacementCollected = 0;
         emi.displacement = 0;
+        emi.dispSize = 0;
 
         emi.modRM = 0;
         emi.sib = 0;
+        m5Reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
+        emi.mode.mode = m5Reg.mode;
+        emi.mode.submode = m5Reg.submode;
     }
 
     void Predecoder::process()
@@ -96,7 +86,7 @@ namespace X86ISA
             switch(state)
             {
               case ResetState:
-                reset();
+                doReset();
                 state = PrefixState;
               case PrefixState:
                 state = doPrefixState(nextByte);
@@ -130,7 +120,10 @@ namespace X86ISA
     {
         uint8_t prefix = Prefixes[nextByte];
         State nextState = PrefixState;
-        if(prefix)
+        // REX prefixes are only recognized in 64 bit mode.
+        if (prefix == RexPrefix && emi.mode.submode != SixtyFourBitMode)
+            prefix = 0;
+        if (prefix)
             consumeByte();
         switch(prefix)
         {
@@ -185,7 +178,7 @@ namespace X86ISA
         State nextState = ErrorState;
         emi.opcode.num++;
         //We can't handle 3+ byte opcodes right now
-        assert(emi.opcode.num < 3);
+        assert(emi.opcode.num < 4);
         consumeByte();
         if(emi.opcode.num == 1 && nextByte == 0x0f)
         {
@@ -193,11 +186,8 @@ namespace X86ISA
             DPRINTF(Predecoder, "Found two byte opcode.\n");
             emi.opcode.prefixA = nextByte;
         }
-        else if(emi.opcode.num == 2 &&
-                (nextByte == 0x0f ||
-                 (nextByte & 0xf8) == 0x38))
+        else if(emi.opcode.num == 2 && (nextByte == 0x38 || nextByte == 0x3A))
         {
-            panic("Three byte opcodes aren't yet supported!\n");
             nextState = OpcodeState;
             DPRINTF(Predecoder, "Found three byte opcode.\n");
             emi.opcode.prefixB = nextByte;
@@ -210,37 +200,38 @@ namespace X86ISA
             //Figure out the effective operand size. This can be overriden to
             //a fixed value at the decoder level.
             int logOpSize;
-            if(/*FIXME long mode*/1)
-            {
-                if(emi.rex.w)
-                    logOpSize = 3; // 64 bit operand size
-                else if(emi.legacy.op)
-                    logOpSize = 1; // 16 bit operand size
-                else
-                    logOpSize = 2; // 32 bit operand size
-            }
-            else if(/*FIXME default 32*/1)
-            {
-                if(emi.legacy.op)
-                    logOpSize = 1; // 16 bit operand size
-                else
-                    logOpSize = 2; // 32 bit operand size
-            }
-            else // 16 bit default operand size
-            {
-                if(emi.legacy.op)
-                    logOpSize = 2; // 32 bit operand size
-                else
-                    logOpSize = 1; // 16 bit operand size
-            }
+            if (emi.rex.w)
+                logOpSize = 3; // 64 bit operand size
+            else if (emi.legacy.op)
+                logOpSize = m5Reg.altOp;
+            else
+                logOpSize = m5Reg.defOp;
+
+            //Set the actual op size
+            emi.opSize = 1 << logOpSize;
+
+            //Figure out the effective address size. This can be overriden to
+            //a fixed value at the decoder level.
+            int logAddrSize;
+            if(emi.legacy.addr)
+                logAddrSize = m5Reg.altAddr;
+            else
+                logAddrSize = m5Reg.defAddr;
+
+            //Set the actual address size
+            emi.addrSize = 1 << logAddrSize;
+
+            //Figure out the effective stack width. This can be overriden to
+            //a fixed value at the decoder level.
+            emi.stackSize = 1 << m5Reg.stack;
 
             //Figure out how big of an immediate we'll retreive based
             //on the opcode.
             int immType = ImmediateType[emi.opcode.num - 1][nextByte];
-            immediateSize = SizeTypeToSize[logOpSize - 1][immType];
-
-            //Set the actual op size
-            emi.opSize = 1 << logOpSize;
+            if (emi.opcode.num == 1 && nextByte >= 0xA0 && nextByte <= 0xA3)
+                immediateSize = SizeTypeToSize[logAddrSize - 1][immType];
+            else
+                immediateSize = SizeTypeToSize[logOpSize - 1][immType];
 
             //Determine what to expect next
             if (UsesModRM[emi.opcode.num - 1][nextByte]) {
@@ -263,31 +254,39 @@ namespace X86ISA
     Predecoder::State Predecoder::doModRMState(uint8_t nextByte)
     {
         State nextState = ErrorState;
-        emi.modRM = nextByte;
+        ModRM modRM;
+        modRM = nextByte;
         DPRINTF(Predecoder, "Found modrm byte %#x.\n", nextByte);
-        if (0) {//FIXME in 16 bit mode
+        if (m5Reg.defOp == 1) {
             //figure out 16 bit displacement size
-            if(nextByte & 0xC7 == 0x06 ||
-                    nextByte & 0xC0 == 0x80)
+            if ((modRM.mod == 0 && modRM.rm == 6) || modRM.mod == 2)
                 displacementSize = 2;
-            else if(nextByte & 0xC0 == 0x40)
+            else if (modRM.mod == 1)
                 displacementSize = 1;
             else
                 displacementSize = 0;
         } else {
             //figure out 32/64 bit displacement size
-            if(nextByte & 0xC6 == 0x04 ||
-                    nextByte & 0xC0 == 0x80)
+            if ((modRM.mod == 0 && modRM.rm == 5) || modRM.mod == 2)
                 displacementSize = 4;
-            else if(nextByte & 0xC0 == 0x40)
+            else if (modRM.mod == 1)
                 displacementSize = 1;
             else
                 displacementSize = 0;
         }
+
+        // The "test" instruction in group 3 needs an immediate, even though
+        // the other instructions with the same actual opcode don't.
+        if (emi.opcode.num == 1 && (modRM.reg & 0x6) == 0) {
+           if (emi.opcode.op == 0xF6)
+               immediateSize = 1;
+           else if (emi.opcode.op == 0xF7)
+               immediateSize = (emi.opSize == 8) ? 4 : emi.opSize;
+        }
+
         //If there's an SIB, get that next.
         //There is no SIB in 16 bit mode.
-        if(nextByte & 0x7 == 4 &&
-                nextByte & 0xC0 != 0xC0) {
+        if (modRM.rm == 4 && modRM.mod != 3) {
                 // && in 32/64 bit mode)
             nextState = SIBState;
         } else if(displacementSize) {
@@ -300,6 +299,7 @@ namespace X86ISA
         }
         //The ModRM byte is consumed no matter what
         consumeByte();
+        emi.modRM = modRM;
         return nextState;
     }
 
@@ -312,7 +312,9 @@ namespace X86ISA
         emi.sib = nextByte;
         DPRINTF(Predecoder, "Found SIB byte %#x.\n", nextByte);
         consumeByte();
-        if(displacementSize) {
+        if (emi.modRM.mod == 0 && emi.sib.base == 5)
+            displacementSize = 4;
+        if (displacementSize) {
             nextState = DisplacementState;
         } else if(immediateSize) {
             nextState = ImmediateState;
@@ -329,14 +331,16 @@ namespace X86ISA
     {
         State nextState = ErrorState;
 
-        getImmediate(displacementCollected,
+        getImmediate(immediateCollected,
                 emi.displacement,
                 displacementSize);
 
         DPRINTF(Predecoder, "Collecting %d byte displacement, got %d bytes.\n",
-                displacementSize, displacementCollected);
+                displacementSize, immediateCollected);
 
-        if(displacementSize == displacementCollected) {
+        if(displacementSize == immediateCollected) {
+            //Reset this for other immediates.
+            immediateCollected = 0;
             //Sign extend the displacement
             switch(displacementSize)
             {
@@ -360,6 +364,8 @@ namespace X86ISA
                 emiIsReady = true;
                 nextState = ResetState;
             }
+
+            emi.dispSize = displacementSize;
         }
         else
             nextState = DisplacementState;
@@ -381,6 +387,9 @@ namespace X86ISA
 
         if(immediateSize == immediateCollected)
         {
+            //Reset this for other immediates.
+            immediateCollected = 0;
+
             //XXX Warning! The following is an observed pattern and might
             //not always be true!
 
@@ -389,8 +398,15 @@ namespace X86ISA
             //Instructions which use true 64 bit immediates won't be
             //affected, and instructions that use true 32 bit immediates
             //won't notice.
-            if(immediateSize == 4)
+            switch(immediateSize)
+            {
+              case 4:
                 emi.immediate = sext<32>(emi.immediate);
+                break;
+              case 1:
+                emi.immediate = sext<8>(emi.immediate);
+            }
+
             DPRINTF(Predecoder, "Collected immediate %#x.\n",
                     emi.immediate);
             emiIsReady = true;