arch-power: Fix fixed-point word shift instructions
authorSandipan Das <sandipan@linux.vnet.ibm.com>
Thu, 7 Jun 2018 12:46:46 +0000 (18:16 +0530)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 24 Jan 2021 03:26:14 +0000 (03:26 +0000)
This fixes the following shift instructions:
  * Shift Left Word (slw[.])
  * Shift Right Word (srw[.])
  * Shift Right Algebraic Word (sraw[.])
  * Shift Right Algebraic Word Immediate (srawi[.])

For 64-bit execution, these instructions should perform
shift operations on only the lower order 32 bits of the
source register instead of all 64 bits.

This also fixes disassembly generation for all of the above.

Change-Id: I18871486d74969244d474eaf0f9d810f06faf50a
Signed-off-by: Sandipan Das <sandipan@linux.vnet.ibm.com>
src/arch/power/insts/integer.cc
src/arch/power/insts/integer.hh
src/arch/power/isa/decoder.isa
src/arch/power/isa/formats/integer.isa

index 2f7e15909a66b5b44b2fb771f131373542c91df1..66e50e2bfd828f8ac4d68cacaf3bf5763997bb19 100644 (file)
@@ -577,8 +577,21 @@ IntShiftOp::generateDisassembly(
         Addr pc, const Loader::SymbolTable *symtab) const
 {
     stringstream ss;
+    bool printSecondSrc = true;
+    bool printShift = false;
 
-    ccprintf(ss, "%-10s ", mnemonic);
+    // Generate the correct mnemonic
+    string myMnemonic(mnemonic);
+
+    // Special cases
+    if (!myMnemonic.compare("srawi")) {
+        printSecondSrc = false;
+        printShift = true;
+    }
+
+    // Additional characters depending on isa bits being set
+    if (rcSet) myMnemonic = myMnemonic + ".";
+    ccprintf(ss, "%-10s ", myMnemonic);
 
     // Print the first destination only
     if (_numDestRegs > 0) {
@@ -591,10 +604,32 @@ IntShiftOp::generateDisassembly(
             ss << ", ";
         }
         printReg(ss, _srcRegIdx[0]);
+
+        // Print the second source register
+        if (printSecondSrc) {
+
+            // If the instruction updates the CR, the destination register
+            // Ra is read and thus, it becomes the second source register
+            // due to its higher precedence over Rb. In this case, it must
+            // be skipped.
+            if (rcSet) {
+                if (_numSrcRegs > 2) {
+                    ss << ", ";
+                    printReg(ss, _srcRegIdx[2]);
+                }
+            } else {
+                if (_numSrcRegs > 1) {
+                    ss << ", ";
+                    printReg(ss, _srcRegIdx[1]);
+                }
+            }
+        }
     }
 
-    // Print the shift
-    ss << ", " << sh;
+    // Print the shift value
+    if (printShift) {
+        ss << ", " << shift;
+    }
 
     return ss.str();
 }
index 4129a34820a70a445109586b18bc02e0315ba27a..a2b65af6ef986d20a92e4e8089d027e2e572da8e 100644 (file)
@@ -587,18 +587,19 @@ class IntImmLogicOp : public IntLogicOp
 
 
 /**
- * Class for integer operations with a shift.
+ * Class for integer operations with a shift value obtained from
+ * a register or an instruction field.
  */
 class IntShiftOp : public IntOp
 {
   protected:
 
-    uint32_t sh;
+    uint32_t shift;
 
     /// Constructor
     IntShiftOp(const char *mnem, MachInst _machInst, OpClass __opClass)
       : IntOp(mnem, _machInst, __opClass),
-        sh(machInst.sh)
+        shift(machInst.sh)
     {
     }
 
index 928cfd856d5f75f9f36951a4dbaa246de86598ff..cf440e04816667de34909b8257b5a4ed8b2ccbfb 100644 (file)
@@ -586,83 +586,68 @@ decode PO default Unknown::unknown() {
                 }
                 Ra = res;
             }});
+        }
 
+        // Integer instructions with a shift value.
+        format IntShiftOp {
             24: slw({{
-                if (Rb & 0x20) {
-                    Ra = 0;
-                } else {
-                    Ra = Rs << (Rb & 0x1f);
+                int32_t shift = Rb_sw;
+                uint32_t res = Rs_uw & ~((shift << 26) >> 31);
+                if (shift != 0) {
+                    shift = shift & 0x1f;
+                    res = res << shift;
                 }
+                Ra = res;
             }});
 
             536: srw({{
-                if (Rb & 0x20) {
-                    Ra = 0;
-                } else  {
-                    Ra = Rs >> (Rb & 0x1f);
+                int32_t shift = Rb_sw;
+                uint32_t res = Rs_uw & ~((shift << 26) >> 31);
+                if (shift != 0) {
+                    shift = shift & 0x1f;
+                    res = res >> shift;
                 }
+                Ra = res;
             }});
 
             792: sraw({{
-                bool shiftSetCA = false;
-                int32_t s = Rs;
-                if (Rb == 0) {
-                    Ra = Rs;
-                    shiftSetCA = true;
-                } else if (Rb & 0x20) {
-                    if (s < 0) {
-                        Ra = (uint32_t)-1;
-                        if (s & 0x7fffffff) {
-                            shiftSetCA = true;
-                        } else {
-                            shiftSetCA = false;
-                        }
-                    } else {
-                        Ra = 0;
-                        shiftSetCA = false;
+                int32_t src = Rs_sw;
+                uint32_t shift = Rb_uw;
+                int64_t res;
+                if ((shift & 0x20) != 0) {
+                    res = src >> 31;
+                    if (res != 0) {
+                        setCA = true;
                     }
                 } else {
-                    Ra = s >> (Rb & 0x1f);
-                    if (s < 0 && (s << (32 - (Rb & 0x1f))) != 0) {
-                        shiftSetCA = true;
+                    if (shift != 0) {
+                        shift = shift & 0x1f;
+                        res = src >> shift;
+                        if (src < 0 && (src & mask(shift)) != 0) {
+                            setCA = true;
+                        }
                     } else {
-                        shiftSetCA = false;
+                        res = src;
                     }
                 }
-                Xer xer1 = XER;
-                if (shiftSetCA) {
-                    xer1.ca = 1;
-                } else {
-                    xer1.ca = 0;
-                }
-                XER = xer1;
-            }});
-        }
+                Ra = res;
+            }},
+            true);
 
-        // Integer logic instructions with a shift value.
-        format IntShiftOp {
             824: srawi({{
-                bool shiftSetCA = false;
-                if (sh == 0) {
-                    Ra = Rs;
-                    shiftSetCA = false;
-                } else {
-                    int32_t s = Rs;
-                    Ra = s >> sh;
-                    if (s < 0 && (s << (32 - sh)) != 0) {
-                        shiftSetCA = true;
-                    } else {
-                        shiftSetCA = false;
+                int32_t src = Rs_sw;
+                int64_t res;
+                if (shift != 0) {
+                    res = src >> shift;
+                    if (src < 0 && (src & mask(shift)) != 0) {
+                        setCA = true;
                     }
-                }
-                Xer xer1 = XER;
-                if (shiftSetCA) {
-                    xer1.ca = 1;
                 } else {
-                    xer1.ca = 0;
+                    res = src;
                 }
-                XER = xer1;
-            }});
+                Ra = res;
+            }},
+            true);
         }
 
         // Generic integer format instructions.
index 057277ffb96c4bcb1669d906434d4d1656304de2..4a9630790a2e064f14850fb668d081f37ee40c5f 100644 (file)
@@ -309,13 +309,26 @@ def format IntLogicOp(code, computeCR0 = 0, inst_flags = []) {{
 }};
 
 
-// Integer instructions with a shift amount. As above, except inheriting
-// from the IntShiftOp class.
-def format IntShiftOp(code, inst_flags = []) {{
+// Integer instructions that perform shift operations. All of these
+// instructions write to Ra and use Rs as a source register. The shift
+// value is obtained from an register or an instruction field. If it
+// from a register, Rb is also used as a source register. In certain
+// situations, the carry bits have to be set and this is dealt with
+// using the 'setCA' boolean in decoder.isa. We need two versions for
+// each instruction to deal with the Rc bit.
+def format IntShiftOp(code, computeCA = 0, inst_flags = []) {{
     dict = {'result':'Ra'}
 
+    # Add code to setup variables and access XER if necessary
+    code  = 'bool setCA M5_VAR_USED = false;\n' + code
+
     # Code when Rc is set
-    code_rc1 = code + readXERCode + computeCR0Code % dict
+    code_rc1 = readXERCode + code + computeCR0Code % dict
+
+    # Add code for calculating the carry, if needed
+    if computeCA:
+        code = readXERCode + code + setCACode + setXERCode
+        code_rc1 += setCACode + setXERCode
 
     # Generate the first class
     (header_output, decoder_output, decode_block, exec_output) = \