x86: Add support for maintaining the x87 tag word
authorAndreas Sandberg <andreas@sandberg.pp.se>
Tue, 18 Jun 2013 14:36:08 +0000 (16:36 +0200)
committerAndreas Sandberg <andreas@sandberg.pp.se>
Tue, 18 Jun 2013 14:36:08 +0000 (16:36 +0200)
The current implementation of the x87 never updates the x87 tag
word. This is currently not a big issue since the simulated x87 never
checks for stack overflows, however this becomes an issue when
switching between a virtualized CPU and a simulated CPU. This
changeset adds support, which is enabled by default, for updating the
tag register to every floating point microop that updates the stack
top using the spm mechanism.

The new tag words is generated by the helper function
X86ISA::genX87Tags(). This function is currently limited to flagging a
stack position as valid or invalid and does not try to distinguish
between the valid, zero, and special states.

src/arch/x86/faults.cc
src/arch/x86/isa/microops/fpop.isa
src/arch/x86/utility.cc
src/arch/x86/utility.hh

index 9953265622632a47efef975c08a41e7e65d7d7ff..aa859052efbb75f648912f3fd5cd24acba6696d1 100644 (file)
@@ -270,6 +270,9 @@ namespace X86ISA
 
         tc->setMiscReg(MISCREG_MXCSR, 0x1f80);
 
+        // Flag all elements on the x87 stack as empty.
+        tc->setMiscReg(MISCREG_FTW, 0xFFFF);
+
         // Update the handy M5 Reg.
         tc->setMiscReg(MISCREG_M5_REG, 0);
         MicroPC entry = X86ISAInst::RomLabels::extern_label_initIntHalt;
index 22d6fbcdad60f127d9a474847068fa10e71a35b5..142138fb25af7290923e01b85a6d06087f429544 100644 (file)
@@ -57,6 +57,7 @@ def template MicroFpOpExecute {{
             {
                 %(code)s;
                 %(flag_code)s;
+                %(tag_code)s;
                 %(top_code)s;
             }
             else
@@ -128,11 +129,20 @@ let {{
             base = "X86ISA::FpOp"
 
             # Get everything ready for the substitution
+            iop_tag = InstObjParams(name, Name + suffix + "TopTag", base,
+                    {"code" : code,
+                     "flag_code" : flag_code,
+                     "cond_check" : cond_check,
+                     "else_code" : else_code,
+                     "tag_code" : "FTW = genX87Tags(FTW, TOP, spm);",
+                     "top_code" : "TOP = (TOP + spm + 8) % 8;",
+                     "op_class" : op_class})
             iop_top = InstObjParams(name, Name + suffix + "Top", base,
                     {"code" : code,
                      "flag_code" : flag_code,
                      "cond_check" : cond_check,
                      "else_code" : else_code,
+                     "tag_code" : ";",
                      "top_code" : "TOP = (TOP + spm + 8) % 8;",
                      "op_class" : op_class})
             iop = InstObjParams(name, Name + suffix, base,
@@ -140,10 +150,14 @@ let {{
                      "flag_code" : flag_code,
                      "cond_check" : cond_check,
                      "else_code" : else_code,
+                     "tag_code" : ";",
                      "top_code" : ";",
                      "op_class" : op_class})
 
             # Generate the actual code (finally!)
+            header_output += MicroFpOpDeclare.subst(iop_tag)
+            decoder_output += MicroFpOpConstructor.subst(iop_tag)
+            exec_output += MicroFpOpExecute.subst(iop_tag)
             header_output += MicroFpOpDeclare.subst(iop_top)
             decoder_output += MicroFpOpConstructor.subst(iop_top)
             exec_output += MicroFpOpExecute.subst(iop_top)
@@ -191,7 +205,7 @@ let {{
         op_class = "FloatAddOp"
 
         def __init__(self, dest, src1, spm=0, \
-                SetStatus=False, dataSize="env.dataSize"):
+                SetStatus=False, UpdateFTW=True, dataSize="env.dataSize"):
             self.dest = dest
             self.src1 = src1
             self.src2 = "InstRegIndex(0)"
@@ -201,6 +215,8 @@ let {{
                 self.className += "Flags"
             if spm:
                 self.className += "Top"
+            if spm and UpdateFTW:
+                self.className += "Tag"
 
         def getAllocator(self, microFlags):
             return '''new %(class_name)s(machInst, macrocodeBlock,
@@ -225,7 +241,7 @@ let {{
         op_class = "FloatAddOp"
 
         def __init__(self, dest, src1, src2, spm=0, \
-                SetStatus=False, dataSize="env.dataSize"):
+                SetStatus=False, UpdateFTW=True, dataSize="env.dataSize"):
             self.dest = dest
             self.src1 = src1
             self.src2 = src2
@@ -235,6 +251,8 @@ let {{
                 self.className += "Flags"
             if spm:
                 self.className += "Top"
+            if spm and UpdateFTW:
+                self.className += "Tag"
 
         def getAllocator(self, microFlags):
             return '''new %(class_name)s(machInst, macrocodeBlock,
@@ -359,10 +377,10 @@ let {{
         flag_code = 'FSW = new_fsw;'
 
     class Compfp(FpBinaryOp):
-        def __init__(self, src1, src2, spm=0, setStatus=False, \
+        def __init__(self, src1, src2, spm=0, setStatus=False, updateFTW=True, \
                 dataSize="env.dataSize"):
             super(Compfp, self).__init__("InstRegIndex(FLOATREG_MICROFP0)", \
-                    src1, src2, spm, setStatus, dataSize)
+                    src1, src2, spm, setStatus, updateFTW, dataSize)
         # This class sets the condition codes in rflags according to the
         # rules for comparing floating point.
         code = '''
index 2398ca0739798345a1e06cc1bdd2a8bca81351f5..3df948986d503dbcd1489c2402da57011dad2f48 100644 (file)
@@ -268,4 +268,24 @@ setRFlags(ThreadContext *tc, uint64_t val)
     tc->setMiscReg(MISCREG_RFLAGS, val & ~(ccFlagMask | cfofMask | DFBit));
 }
 
+uint16_t
+genX87Tags(uint16_t ftw, uint8_t top, int8_t spm)
+{
+    const uint8_t new_top((top + spm + 8) % 8);
+
+    if (spm > 0) {
+        // Removing elements from the stack. Flag the elements as empty.
+        for (int i = top; i != new_top; i = (i + 1 + 8) % 8)
+            ftw |= 0x3 << (2 * i);
+    } else if (spm < 0) {
+        // Adding elements to the stack. Flag the new elements as
+        // valid. We should ideally decode them and "do the right
+        // thing".
+        for (int i = new_top; i != top; i = (i + 1 + 8) % 8)
+            ftw &= ~(0x3 << (2 * i));
+    }
+
+    return ftw;
+}
+
 } // namespace X86_ISA
index 48840ac77f9d221fb2f1190b2632cedef68f0315..24aca3e0ad58f754c4885689d2b601831fc4e2a4 100644 (file)
@@ -141,6 +141,21 @@ namespace X86ISA
     inline uint64_t getDoubleBits(double val) {
         return *(uint64_t *)(&val);
     }
+
+    /**
+     * Generate and updated x87 tag register after a push/pop
+     * operation.
+     *
+     * @note There is currently no support for setting other tags than
+     * valid and invalid. A real x87 will set the tag value to zero or
+     * special for some special floating point values.
+     *
+     * @param ftw Current value of the FTW register.
+     * @param top Current x87 TOP value.
+     * @param spm Stack displacement.
+     * @return New value of the FTW register.
+     */
+    uint16_t genX87Tags(uint16_t ftw, uint8_t top, int8_t spm);
 }
 
 #endif // __ARCH_X86_UTILITY_HH__