arch-power: Add fixed-point doubleword rotate instructions
authorSandipan Das <sandipan@linux.vnet.ibm.com>
Thu, 7 Jun 2018 13:30:23 +0000 (19:00 +0530)
committerSandipan Das <sandipan@linux.vnet.ibm.com>
Thu, 7 Jun 2018 13:33:04 +0000 (19:03 +0530)
This adds the following rotate instructions:
  * Rotate Left Doubleword Immediate then Clear Left (rldicl[.])
  * Rotate Left Doubleword Immediate then Clear Right (rldicr[.])
  * Rotate Left Doubleword Immediate then Clear (rldic[.])
  * Rotate Left Doubleword then Clear Left (rldcl[.])
  * Rotate Left Doubleword then Clear Right (rldcr[.])
  * Rotate Left Doubleword Immediate then Mask Insert (rldimi[.])

Change-Id: I27520314e738e5bed92bf07c1150943c9f83e881
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 ce4ab463d951da36ce3150fde62568ed703df2b5..1a74b80f873aa593dbc1de348023bc158dfd817a 100644 (file)
@@ -780,3 +780,86 @@ IntRotateOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
 
     return ss.str();
 }
+
+string
+IntConcatRotateOp::generateDisassembly(Addr pc,
+                                       const SymbolTable *symtab) const
+{
+    stringstream ss;
+    bool printSecondSrc = false;
+    bool printShift = true;
+    bool printMaskBeg = true;
+
+    // Generate the correct mnemonic
+    string myMnemonic(mnemonic);
+
+    // Special cases
+    if (!myMnemonic.compare("rldicl")) {
+        if (maskBeg == 0) {
+            myMnemonic = "rotldi";
+            printMaskBeg = false;
+        } else if (shift == 0) {
+            myMnemonic = "clrldi";
+            printShift = false;
+        }
+    } else if (!myMnemonic.compare("rldcl")) {
+        if (maskBeg == 0) {
+            myMnemonic = "rotld";
+            printMaskBeg = false;
+        }
+        printSecondSrc = true;
+        printShift = false;
+    } else if (!myMnemonic.compare("rldcr")) {
+        printSecondSrc = true;
+        printShift = false;
+    }
+
+    // Additional characters depending on isa bits being set
+    if (rcSet) myMnemonic = myMnemonic + ".";
+    ccprintf(ss, "%-10s ", myMnemonic);
+
+    // Print the first destination only
+    if (_numDestRegs > 0) {
+        printReg(ss, _destRegIdx[0]);
+    }
+
+    // Print the first source register
+    if (_numSrcRegs > 0) {
+        if (_numDestRegs > 0) {
+            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 amount
+    if (printShift) {
+        ss << ", " << shift;
+    }
+
+    // Print the mask bound
+    if (printMaskBeg) {
+        ss << ", " << maskBeg;
+    }
+
+    return ss.str();
+}
index 95d64b3383240f7c6f9d15b5d40c69ef7024856a..afcf928e89750806fb1aa097daa90fe40adc3e97 100644 (file)
@@ -679,6 +679,50 @@ class IntRotateOp : public IntShiftOp
             Addr pc, const SymbolTable *symtab) const override;
 };
 
+
+/**
+ * Class for integer rotate operations with a shift amount obtained
+ * from a register or by concatenating immediate fields and the first
+ * and last bits of a mask obtained by concatenating immediate fields.
+ */
+class IntConcatRotateOp : public IntConcatShiftOp
+{
+  protected:
+
+    uint32_t maskBeg;
+    uint32_t maskEnd;
+
+    /// Constructor
+    IntConcatRotateOp(const char *mnem, MachInst _machInst, OpClass __opClass)
+      : IntConcatShiftOp(mnem, _machInst, __opClass),
+        maskBeg(((uint32_t)machInst.mbn << 5) | machInst.mb),
+        maskEnd(((uint32_t)machInst.men << 5) | machInst.mb)
+    {
+    }
+
+    inline uint64_t
+    rotate(uint64_t rs, uint32_t sh) const
+    {
+        sh = sh & 0x3f;
+        return (rs << sh) | (rs >> (64 - sh));
+    }
+
+    inline uint64_t
+    bitmask(uint32_t mb, uint32_t me) const
+    {
+        mb = mb & 0x3f;
+        me = me & 0x3f;
+        if (mb <= me) {
+            return mask(63 - mb, 63 - me);
+        } else {
+            return ~mask(63 - (me + 1), 63 - (mb - 1));
+        }
+    }
+
+    std::string generateDisassembly(
+            Addr pc, const SymbolTable *symtab) const override;
+};
+
 } // namespace PowerISA
 
 #endif //__ARCH_POWER_INSTS_INTEGER_HH__
index 5933bca480a920b9c1d9872d00490e34c53fbd14..ef93bdfd35ca7c57a65e7846793d0429f49bcb1a 100644 (file)
@@ -984,6 +984,84 @@ decode PO default Unknown::unknown() {
         }
     }
 
+    // These instructions are of MD form and use bits 27 - 29 as XO.
+    30: decode MD_XO {
+        format IntConcatRotateOp {
+            0: rldicl({{
+                uint64_t res;
+                if (shift != 0) {
+                    res = rotate(Rs, shift);
+                } else {
+                    res = Rs;
+                }
+                res = res & bitmask(maskBeg, 63);
+                Ra = res;
+            }});
+
+            1: rldicr({{
+                uint64_t res;
+                if (shift != 0) {
+                    res = rotate(Rs, shift);
+                } else {
+                    res = Rs;
+                }
+                res = res & bitmask(0, maskEnd);
+                Ra = res;
+            }});
+
+            2: rldic({{
+                uint64_t res;
+                if (shift != 0) {
+                    res = rotate(Rs, shift);
+                } else {
+                    res = Rs;
+                }
+                res = res & bitmask(maskBeg, ~shift);
+                Ra = res;
+            }});
+
+            3: rldimi({{
+                uint64_t res, mask;
+                mask = bitmask(maskBeg, ~shift);
+                if (shift != 0) {
+                    res = rotate(Rs, shift);
+                } else {
+                    res = Rs;
+                }
+                res = res & mask;
+                res = res | (Ra & ~mask);
+                Ra = res;
+            }});
+
+            // These instructions are of MDS form and use bits 27 - 30 as XO.
+            default: decode MDS_XO {
+                8: rldcl({{
+                    uint64_t res;
+                    uint32_t shift = Rb & 0x3f;
+                    if (shift != 0) {
+                        res = rotate(Rs, shift);
+                    } else {
+                        res = Rs;
+                    }
+                    res = res & bitmask(maskBeg, 63);
+                    Ra = res;
+                }});
+
+                9: rldcr({{
+                    uint64_t res;
+                    uint32_t shift = Rb & 0x3f;
+                    if (shift != 0) {
+                        res = rotate(Rs, shift);
+                    } else {
+                        res = Rs;
+                    }
+                    res = res & bitmask(0, maskEnd);
+                    Ra = res;
+                }});
+            }
+        }
+    }
+
     format LoadDispOp {
         48: lfs({{ Ft_sf = Mem_sf; }});
         50: lfd({{ Ft = Mem_df; }});
index 78f8062db670c8597a610e944e4ba0ab737655ce..8f23084f1b0057af7cdaa23d79f3f7fe288c0af1 100644 (file)
@@ -551,3 +551,32 @@ def format IntRotateOp(code, inst_flags = []) {{
     decoder_output += decoder_output_rc1
     exec_output += exec_output_rc1
 }};
+
+
+// Everything is same as above except that the immediates may need to be
+// concatenated to get the final values for the mask bounds or the shift
+// value. We need two versions for each instruction to deal with the Rc
+// bit.
+def format IntConcatRotateOp(code, inst_flags = []) {{
+
+    # The result is always in Ra
+    dict = {'result':'Ra'}
+
+    # Code when Rc is set
+    code_rc1 = readXERCode + code + computeCR0Code % dict
+
+    # Generate the first class
+    (header_output, decoder_output, decode_block, exec_output) = \
+        GenAluOp(name, Name, 'IntConcatRotateOp', code, inst_flags,
+                 CheckRcDecode, BasicConstructor)
+
+    # Generate the second class
+    (header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \
+        GenAluOp(name, Name + 'RcSet', 'IntConcatRotateOp', code_rc1,
+                 inst_flags, CheckRcDecode, IntRcConstructor)
+
+    # Finally, add to the other outputs
+    header_output += header_output_rc1
+    decoder_output += decoder_output_rc1
+    exec_output += exec_output_rc1
+}};