arch-power: Add doubleword rotate instructions
authorSandipan Das <sandipan@linux.ibm.com>
Sat, 6 Feb 2021 11:52:12 +0000 (17:22 +0530)
committerSandipan Das <sandipan@linux.ibm.com>
Mon, 15 Feb 2021 08:32:38 +0000 (14:02 +0530)
This introduces a new class and a new format for MD and
MDS form instructions where the shift amount, mask begin
and mask end are specified by two fields that must be
concatenated and adds the following 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: Id7f1f24032242ccfdfda2f1aefd6fe9f0331f610
Signed-off-by: Sandipan Das <sandipan@linux.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 aaa79253ff9f7fedb0efa8c38cb6ca612a4f51d0..0631749e2e9bcfebb63168b864e0b66678fda866 100644 (file)
@@ -795,3 +795,86 @@ IntRotateOp::generateDisassembly(
 
     return ss.str();
 }
+
+std::string
+IntConcatRotateOp::generateDisassembly(
+        Addr pc, const Loader::SymbolTable *symtab) const
+{
+    std::stringstream ss;
+    bool printSecondSrc = false;
+    bool printShift = true;
+    bool printMaskBeg = true;
+
+    // Generate the correct mnemonic
+    std::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 6d39a5fed3df35c9fbc408e1ffa48029ef004a9e..59566e88b5f17fc2066b9970a30a96ee5459ca0a 100644 (file)
@@ -689,6 +689,50 @@ class IntRotateOp : public IntShiftOp
             Addr pc, const Loader::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 Loader::SymbolTable *symtab) const override;
+};
+
 } // namespace PowerISA
 
 #endif //__ARCH_POWER_INSTS_INTEGER_HH__
index 1c67d3aaa98a5b813d2e108ff4bdb517ca4e60c5..73b0973f7d061074697217c3fcc175ab02ac0453 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 bc52340ecd17aa3f5dd247d7ea7207c3fb0706b6..6f8d03861edd994bab7d01dc0237a8b5595579d4 100644 (file)
@@ -554,3 +554,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
+}};