arch-power: Fix fixed-point compare instructions
authorSandipan Das <sandipan@linux.vnet.ibm.com>
Thu, 7 Jun 2018 08:53:20 +0000 (14:23 +0530)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 24 Jan 2021 03:24:22 +0000 (03:24 +0000)
This fixes the following compare instructions:
  * Compare (cmp)
  * Compare Logical (cmpl)
  * Compare Immediate (cmpi)
  * Compare Logical Immediate (cmpli)

Instead of always doing a 32-bit comparison, these instructions
now use the length field to determine the type of comparison to
be done. The comparison can either be based on the lower order
32 bits or on all 64 bits of the values.

This also fixes disassembly generation for all of the above.

Change-Id: I6a9f783efa9ef2f2ef3c16eada61074d6f798a20
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
src/arch/power/types.hh

index e5692bb2285b479da58895ee65190097793a2463..b55f75ccd61c278c4c977deda0c53ee601af4282 100644 (file)
@@ -46,7 +46,7 @@ IntOp::generateDisassembly(Addr pc, const Loader::SymbolTable *symtab) const
     if (!myMnemonic.compare("or") && _srcRegIdx[0] == _srcRegIdx[1]) {
         myMnemonic = "mr";
         printSecondSrc = false;
-    } else if (!myMnemonic.compare("mtlr") || !myMnemonic.compare("cmpi")) {
+    } else if (!myMnemonic.compare("mtlr")) {
         printDest = false;
     } else if (!myMnemonic.compare("mflr")) {
         printSrcs = false;
@@ -106,7 +106,8 @@ IntImmOp::generateDisassembly(Addr pc, const Loader::SymbolTable *symtab) const
 
 
 string
-IntArithOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+IntArithOp::generateDisassembly(
+        Addr pc, const Loader::SymbolTable *symtab) const
 {
     stringstream ss;
     bool printSecondSrc = true;
@@ -163,7 +164,8 @@ IntArithOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
 
 
 string
-IntImmArithOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+IntImmArithOp::generateDisassembly(
+        Addr pc, const Loader::SymbolTable *symtab) const
 {
     stringstream ss;
     bool negateSimm = false;
@@ -276,6 +278,185 @@ IntDispArithOp::generateDisassembly(
 }
 
 
+string
+IntCompOp::generateDisassembly(
+        Addr pc, const Loader::SymbolTable *symtab) const
+{
+    stringstream ss;
+    bool printFieldPrefix = false;
+    bool printLength = true;
+
+    // Generate the correct mnemonic
+    string myMnemonic(mnemonic);
+
+    // Special cases
+    if (!myMnemonic.compare("cmp")) {
+        if (length) {
+            myMnemonic = "cmpd";
+        } else {
+            myMnemonic = "cmpw";
+        }
+        printFieldPrefix = true;
+        printLength = false;
+    } else if (!myMnemonic.compare("cmpl")) {
+        if (length) {
+            myMnemonic = "cmpld";
+        } else {
+            myMnemonic = "cmplw";
+        }
+        printFieldPrefix = true;
+        printLength = false;
+    }
+
+    ccprintf(ss, "%-10s ", myMnemonic);
+
+    // Print the first destination only
+    if (printFieldPrefix) {
+        if (field > 0) {
+            ss << "cr" << field;
+        }
+    } else {
+        ss << field;
+    }
+
+    // Print the length
+    if (printLength) {
+        if (!printFieldPrefix || field > 0) {
+            ss << ", ";
+        }
+        ss << length;
+    }
+
+    // Print the first source register
+    if (_numSrcRegs > 0) {
+        if (!printFieldPrefix || field > 0 || printLength) {
+            ss << ", ";
+        }
+        printReg(ss, _srcRegIdx[0]);
+
+        // Print the second source register
+        if (_numSrcRegs > 1) {
+            ss << ", ";
+            printReg(ss, _srcRegIdx[1]);
+        }
+    }
+
+    return ss.str();
+}
+
+
+string
+IntImmCompOp::generateDisassembly(
+        Addr pc, const Loader::SymbolTable *symtab) const
+{
+    stringstream ss;
+    bool printFieldPrefix = false;
+    bool printLength = true;
+
+    // Generate the correct mnemonic
+    string myMnemonic(mnemonic);
+
+    // Special cases
+    if (!myMnemonic.compare("cmpi")) {
+        if (length) {
+            myMnemonic = "cmpdi";
+        } else {
+            myMnemonic = "cmpwi";
+        }
+        printFieldPrefix = true;
+        printLength = false;
+    }
+
+    ccprintf(ss, "%-10s ", myMnemonic);
+
+    // Print the first destination only
+    if (printFieldPrefix) {
+        if (field > 0) {
+            ss << "cr" << field;
+        }
+    } else {
+        ss << field;
+    }
+
+    // Print the length
+    if (printLength) {
+        if (!printFieldPrefix || field > 0) {
+            ss << ", ";
+        }
+        ss << length;
+    }
+
+    // Print the first source register
+    if (_numSrcRegs > 0) {
+        if (!printFieldPrefix || field > 0 || printLength) {
+            ss << ", ";
+        }
+        printReg(ss, _srcRegIdx[0]);
+    }
+
+    // Print the immediate value
+    ss << ", " << simm;
+
+    return ss.str();
+}
+
+
+string
+IntImmCompLogicOp::generateDisassembly(Addr pc,
+                                       const Loader::SymbolTable *symtab) const
+{
+    stringstream ss;
+    bool printFieldPrefix = false;
+    bool printLength = true;
+
+    // Generate the correct mnemonic
+    string myMnemonic(mnemonic);
+
+    // Special cases
+    if (!myMnemonic.compare("cmpli")) {
+        if (length) {
+            myMnemonic = "cmpldi";
+        } else {
+            myMnemonic = "cmplwi";
+        }
+        printFieldPrefix = true;
+        printLength = false;
+    }
+
+    ccprintf(ss, "%-10s ", myMnemonic);
+
+    // Print the first destination only
+    if (printFieldPrefix) {
+        if (field > 0) {
+            ss << "cr" << field;
+        }
+    } else {
+        ss << field;
+    }
+
+    // Print the mode
+    if (printLength) {
+        if (!printFieldPrefix || field > 0) {
+            ss << ", ";
+        }
+        ss << length;
+    }
+
+    // Print the first source register
+    if (_numSrcRegs > 0) {
+        if (!printFieldPrefix || field > 0 || printLength) {
+            ss << ", ";
+        }
+        printReg(ss, _srcRegIdx[0]);
+    }
+
+    // Print the immediate value
+    ss << ", " << uimm;
+
+    return ss.str();
+}
+
+
 string
 IntShiftOp::generateDisassembly(
         Addr pc, const Loader::SymbolTable *symtab) const
index 61602af965e1610c5ed9ebf246e8760fecafb3db..c691ad39b1f48efaaeed150b1a144f81f2e39b82 100644 (file)
@@ -414,6 +414,71 @@ class IntDispArithOp : public IntArithOp
 };
 
 
+/**
+ * Class for integer compare operations.
+ */
+class IntCompOp : public IntOp
+{
+  protected:
+
+    uint32_t length;
+    uint32_t field;
+
+    /// Constructor
+    IntCompOp(const char *mnem, MachInst _machInst, OpClass __opClass)
+      : IntOp(mnem, _machInst, __opClass),
+        length(machInst.l),
+        field(machInst.bf)
+    {
+    }
+
+    std::string generateDisassembly(
+            Addr pc, const SymbolTable *symtab) const override;
+};
+
+
+/**
+ * Class for integer immediate compare operations.
+ */
+class IntImmCompOp : public IntCompOp
+{
+  protected:
+
+    int32_t simm;
+
+    /// Constructor
+    IntImmCompOp(const char *mnem, MachInst _machInst, OpClass __opClass)
+      : IntCompOp(mnem, _machInst, __opClass),
+        simm((int16_t)machInst.si)
+    {
+    }
+
+    std::string generateDisassembly(
+            Addr pc, const SymbolTable *symtab) const override;
+};
+
+
+/**
+ * Class for integer immediate compare logical operations.
+ */
+class IntImmCompLogicOp : public IntCompOp
+{
+  protected:
+
+    uint32_t uimm;
+
+    /// Constructor
+    IntImmCompLogicOp(const char *mnem, MachInst _machInst, OpClass __opClass)
+      : IntCompOp(mnem, _machInst, __opClass),
+        uimm(machInst.ui)
+    {
+    }
+
+    std::string generateDisassembly(
+            Addr pc, const SymbolTable *symtab) const override;
+};
+
+
 /**
  * Class for integer operations with a shift.
  */
index 4857616b68829ae3761bdfb089936760a3be4e43..bf1eaf941f3f323e65828b0bbf4543b9208ecdad 100644 (file)
@@ -250,19 +250,26 @@ decode PO default Unknown::unknown() {
         }
     }
 
-    format IntImmOp {
-        10: cmpli({{
-            Xer xer = XER;
-            uint32_t cr = makeCRField(Ra, (uint32_t)uimm, xer.so);
-            CR = insertCRField(CR, BF, cr);
-            }});
+    format IntImmCompOp {
         11: cmpi({{
-            Xer xer = XER;
-            uint32_t cr = makeCRField(Ra_sw, (int32_t)imm, xer.so);
-            CR = insertCRField(CR, BF, cr);
-            }});
+            if (length) {
+                cr = makeCRField(Ra_sd, simm, xer.so);
+            } else {
+                cr = makeCRField((int32_t)Ra_sd, simm, xer.so);
+            }
+        }});
     }
 
+    format IntImmCompLogicOp {
+        10: cmpli({{
+            if (length) {
+                cr = makeCRField(Ra, uimm, xer.so);
+            } else {
+                cr = makeCRField((uint32_t)Ra, uimm, xer.so);
+            }
+        }});
+     }
+
     format IntImmLogicOp {
         24: ori({{ Ra = Rs | uimm; }});
         25: oris({{ Ra = Rs | (uimm << 16); }});
@@ -451,17 +458,21 @@ decode PO default Unknown::unknown() {
             }});
         }
 
-        format IntOp {
+        format IntCompOp {
             0: cmp({{
-                Xer xer = XER;
-                uint32_t cr = makeCRField(Ra_sw, Rb_sw, xer.so);
-                CR = insertCRField(CR, BF, cr);
+                if (length) {
+                    cr = makeCRField(Ra_sd, Rb_sd, xer.so);
+                } else {
+                    cr = makeCRField((int32_t)Ra_sd, (int32_t)Rb_sd, xer.so);
+                }
             }});
 
             32: cmpl({{
-                Xer xer = XER;
-                uint32_t cr = makeCRField(Ra, Rb, xer.so);
-                CR = insertCRField(CR, BF, cr);
+                if (length) {
+                    cr = makeCRField(Ra, Rb, xer.so);
+                } else {
+                    cr = makeCRField((uint32_t)Ra, (uint32_t)Rb, xer.so);
+                }
             }});
         }
 
index d4a60604f362ff02929faaea0a8653ff97b589b3..3fa058befc3c9b70fa9fa459d36e72c2194fc136 100644 (file)
@@ -221,6 +221,57 @@ def format IntDispArithOp(code, inst_flags = []) {{
 }};
 
 
+// Integer compare instructions.
+def format IntCompOp(code, inst_flags = []) {{
+
+    # Add code to setup variables
+    code = 'uint32_t cr M5_VAR_USED = 0;\n' + code
+    code += 'CR = insertCRField(CR, field, cr);\n'
+
+    # Add code to access XER
+    code = readXERCode + code
+
+    # Generate the class
+    (header_output, decoder_output, decode_block, exec_output) = \
+        GenAluOp(name, Name, 'IntCompOp', code, inst_flags, BasicDecode,
+                 BasicConstructor)
+}};
+
+
+// Integer immediate compare instructions.
+def format IntImmCompOp(code, inst_flags = []) {{
+
+    # Add code to setup variables
+    code = 'uint32_t cr M5_VAR_USED = 0;\n' + code
+    code += 'CR = insertCRField(CR, field, cr);\n'
+
+    # Add code to access XER
+    code = readXERCode + code
+
+    # Generate the class
+    (header_output, decoder_output, decode_block, exec_output) = \
+        GenAluOp(name, Name, 'IntImmCompOp', code, inst_flags, BasicDecode,
+                 BasicConstructor)
+}};
+
+
+// Integer immediate compare logical instructions.
+def format IntImmCompLogicOp(code, inst_flags = []) {{
+
+    # Add code to setup variables
+    code = 'uint32_t cr M5_VAR_USED = 0;\n' + code
+    code += 'CR = insertCRField(CR, field, cr);\n'
+
+    # Add code to access XER
+    code = readXERCode + code
+
+    # Generate the class
+    (header_output, decoder_output, decode_block, exec_output) = \
+        GenAluOp(name, Name, 'IntImmCompLogicOp', code, inst_flags,
+                 BasicDecode, BasicConstructor)
+}};
+
+
 // Integer instructions that perform logic operations. The result is
 // always written into Ra. All instructions have 2 versions depending on
 // whether the Rc bit is set to compute the CR0 code. This is determined
index 5fc887e444510bba197b00ebd5bbdfd60fa4cfa6..db03781fbc6e0310019a2d0a7cbbce78e022f5dc 100644 (file)
@@ -51,12 +51,16 @@ BitUnion32(ExtMachInst)
 
     // Immediate fields
     Bitfield<15,  0> si;
+    Bitfield<15,  0> ui;
     Bitfield<15,  0> d;
     Bitfield<15,  2> ds;
     Bitfield<15,  6> d0;
     Bitfield<20, 16> d1;
     Bitfield< 1,  0> d2;
 
+    // Compare fields
+    Bitfield<21>     l;
+
     // Special purpose register identifier
     Bitfield<20, 11> spr;
     Bitfield<25,  2> li;