From: Sandipan Das Date: Thu, 7 Jun 2018 13:16:02 +0000 (+0530) Subject: arch-power: Fix fixed-point word rotate instructions X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=55710d831d28834300925006c3517dfe859eeef8;p=gem5.git 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 --- diff --git a/src/arch/power/insts/integer.cc b/src/arch/power/insts/integer.cc index af61fa700..b5edc4e48 100644 --- a/src/arch/power/insts/integer.cc +++ b/src/arch/power/insts/integer.cc @@ -705,8 +705,40 @@ IntRotateOp::generateDisassembly( Addr pc, const Loader::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) { @@ -719,10 +751,40 @@ IntRotateOp::generateDisassembly( 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 5e5b7eb23..a2eaaa52b 100644 --- a/src/arch/power/insts/integer.hh +++ b/src/arch/power/insts/integer.hh @@ -631,34 +631,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 1603e86ca..432dd118c 100644 --- a/src/arch/power/isa/decoder.isa +++ b/src/arch/power/isa/decoder.isa @@ -282,10 +282,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 352460695..d8c09d5d2 100644 --- a/src/arch/power/isa/formats/integer.isa +++ b/src/arch/power/isa/formats/integer.isa @@ -521,15 +521,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