From 50da51cc9448cf59d7a85491135f3e1c2260ae39 Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Thu, 7 Jun 2018 18:46:02 +0530 Subject: [PATCH] arch-power: Fix fixed-point word rotate instructions This fixes the following rotate instructions: * Rotate Left Word Immediate then And with Mask (rlwinm[.]) * Rotate Left Word then And with Mask (rlwnm[.]) * Rotate Left Word Immediate then Mask Insert (rlwimi[.]) For 64-bit execution, these instructions should perform rotate operations on a 64-bit value formed by concatenating two copies of the lower order 32 bits of the value in the source register. This also fixes disassembly generation for all of the above. Change-Id: Iccd8c6ad10a26d66dcecd64c8f1f8118ec8c1278 Signed-off-by: Sandipan Das --- src/arch/power/insts/integer.cc | 68 ++++++++++++++++++++++++-- src/arch/power/insts/integer.hh | 42 ++++++++++------ src/arch/power/isa/decoder.isa | 25 ++++++++-- src/arch/power/isa/formats/integer.isa | 10 ++-- 4 files changed, 119 insertions(+), 26 deletions(-) diff --git a/src/arch/power/insts/integer.cc b/src/arch/power/insts/integer.cc index 090ec4802..ce4ab463d 100644 --- a/src/arch/power/insts/integer.cc +++ b/src/arch/power/insts/integer.cc @@ -697,8 +697,40 @@ string IntRotateOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const { stringstream ss; + bool printSecondSrc = true; + bool printShift = true; + bool printMaskBeg = true; + bool printMaskEnd = true; - ccprintf(ss, "%-10s ", mnemonic); + // Generate the correct mnemonic + string myMnemonic(mnemonic); + + // Special cases + if (!myMnemonic.compare("rlwinm")) { + if (maskBeg == 0 && maskEnd == 31) { + myMnemonic = "rotlwi"; + printMaskBeg = false; + printMaskEnd = false; + } else if (shift == 0 && maskEnd == 31) { + myMnemonic = "clrlwi"; + printShift = false; + printMaskEnd = false; + } + printSecondSrc = false; + } else if (!myMnemonic.compare("rlwnm")) { + if (maskBeg == 0 && maskEnd == 31) { + myMnemonic = "rotlw"; + printMaskBeg = false; + printMaskEnd = false; + } + printShift = false; + } else if (!myMnemonic.compare("rlwimi")) { + printSecondSrc = 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) { @@ -711,10 +743,40 @@ IntRotateOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const 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 value + if (printShift) { + ss << ", " << shift; } - // Print the shift, mask begin and mask end - ss << ", " << sh << ", " << mb << ", " << me; + // Print the mask bounds + if (printMaskBeg) { + ss << ", " << maskBeg; + } + if (printMaskEnd) { + ss << ", " << maskEnd; + } return ss.str(); } diff --git a/src/arch/power/insts/integer.hh b/src/arch/power/insts/integer.hh index 15a2b9fc3..95d64b338 100644 --- a/src/arch/power/insts/integer.hh +++ b/src/arch/power/insts/integer.hh @@ -633,34 +633,46 @@ class IntConcatShiftOp : public IntOp /** - * Class for integer rotate operations. + * Class for integer rotate operations with a shift amount obtained + * from a register or an immediate and the first and last bits of a + * mask obtained from immediates. */ class IntRotateOp : public IntShiftOp { protected: - uint32_t mb; - uint32_t me; - uint32_t fullMask; + uint32_t maskBeg; + uint32_t maskEnd; /// Constructor IntRotateOp(const char *mnem, MachInst _machInst, OpClass __opClass) : IntShiftOp(mnem, _machInst, __opClass), - mb(machInst.mb), - me(machInst.me) + maskBeg(machInst.mb), + maskEnd(machInst.me) { - if (me >= mb) { - fullMask = mask(31 - mb, 31 - me); - } else { - fullMask = ~mask(31 - (me + 1), 31 - (mb - 1)); - } } - uint32_t - rotateValue(uint32_t rs, uint32_t shift) const + inline uint64_t + rotate(uint32_t rs, uint32_t sh) const { - uint32_t n = shift & 31; - return (rs << n) | (rs >> (32 - n)); + uint64_t res; + sh = sh & 0x1f; + res = rs; + res = (res << 32) | res; + res = (res << sh) | (res >> (32 - sh)); + return res; + } + + inline uint64_t + bitmask(uint32_t mb, uint32_t me) const + { + mb = mb & 0x1f; + me = me & 0x1f; + if (mb <= me) { + return mask(31 - mb, 31 - me); + } else { + return ~mask(31 - (me + 1), 31 - (mb - 1)); + } } std::string generateDisassembly( diff --git a/src/arch/power/isa/decoder.isa b/src/arch/power/isa/decoder.isa index af710edbc..5933bca48 100644 --- a/src/arch/power/isa/decoder.isa +++ b/src/arch/power/isa/decoder.isa @@ -284,10 +284,27 @@ decode PO default Unknown::unknown() { } format IntRotateOp { - 21: rlwinm({{ Ra = rotateValue(Rs, sh) & fullMask; }}); - 23: rlwnm({{ Ra = rotateValue(Rs, Rb) & fullMask; }}); - 20: rlwimi({{ Ra = (rotateValue(Rs, sh) & fullMask) | - (Ra & ~fullMask); }}); + 21: rlwinm({{ + uint64_t res; + res = rotate(Rs, shift); + res = res & bitmask(maskBeg, maskEnd); + Ra = res; + }}); + + 23: rlwnm({{ + uint64_t res; + res = rotate(Rs, Rb); + res = res & bitmask(maskBeg, maskEnd); + Ra = res; + }}); + + 20: rlwimi({{ + uint64_t res, mask; + mask = bitmask(maskBeg, maskEnd); + res = rotate(Rs, shift); + res = (res & mask) | (Ra & ~mask); + Ra = res; + }}); } // There are a large number of instructions that have the same primary diff --git a/src/arch/power/isa/formats/integer.isa b/src/arch/power/isa/formats/integer.isa index 8f8c2bd41..78f8062db 100644 --- a/src/arch/power/isa/formats/integer.isa +++ b/src/arch/power/isa/formats/integer.isa @@ -523,15 +523,17 @@ def format IntConcatShiftOp(code, computeCA = 0, inst_flags = []) {{ }}; -// A special format for rotate instructions which use certain fields -// from the instruction's binary encoding. We need two versions for each -// instruction to deal with the Rc bit. +// Integer instructions with or without immediate that perform rotate +// operations. All instructions write to Ra and use Rs as a source +// register. If immediate is not used, Rb is also used as a source +// register. We need two versions for each instruction to deal with +// the Rc bit. def format IntRotateOp(code, inst_flags = []) {{ # The result is always in Ra dict = {'result':'Ra'} - # Setup the code for when Rc is set + # Code when Rc is set code_rc1 = readXERCode + code + computeCR0Code % dict # Generate the first class -- 2.30.2