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)
committerSandipan Das <sandipan@linux.vnet.ibm.com>
Thu, 7 Jun 2018 11:07:31 +0000 (16:37 +0530)
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 a1bf84249ecd29b79c3138a0696352143a3b311a..8f7956277e032e02c996decc1ee33b7b64d860ea 100644 (file)
@@ -48,7 +48,7 @@ IntOp::generateDisassembly(Addr pc, const 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;
@@ -277,6 +277,183 @@ IntDispArithOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
 }
 
 
+string
+IntCompOp::generateDisassembly(Addr pc, const 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 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 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 SymbolTable *symtab) const
 {
index 44a7678dbea85bb223a10ca31510f41646a68419..d035f512e5e6505fcd222c03e865bfba1a8a130d 100644 (file)
@@ -416,6 +416,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 43c62afce9d9e6058b24c8c8659512a2d1085597..73b68bfd88dcdf49a68c6ad9ee0aa4ad941e03f8 100644 (file)
@@ -252,19 +252,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); }});
@@ -453,17 +460,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 54c35ebcafb1c15209a4e572b7498eb410796337..e5e6d2db0e1bd5683cfb503470461cd133ac029e 100644 (file)
@@ -223,6 +223,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 8f499bbf1b3ecc115a235f12e4e0eeeb48c4ed52..b0edce81c63baae728236c24ee4831917d204618 100644 (file)
@@ -53,12 +53,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;