From 48a67132a8954a49e9c7cf93569338e90baf5038 Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Sat, 6 Feb 2021 17:22:12 +0530 Subject: [PATCH] arch-power: Add doubleword rotate instructions 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 --- src/arch/power/insts/integer.cc | 83 ++++++++++++++++++++++++++ src/arch/power/insts/integer.hh | 44 ++++++++++++++ src/arch/power/isa/decoder.isa | 78 ++++++++++++++++++++++++ src/arch/power/isa/formats/integer.isa | 29 +++++++++ 4 files changed, 234 insertions(+) diff --git a/src/arch/power/insts/integer.cc b/src/arch/power/insts/integer.cc index aaa79253f..0631749e2 100644 --- a/src/arch/power/insts/integer.cc +++ b/src/arch/power/insts/integer.cc @@ -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(); +} diff --git a/src/arch/power/insts/integer.hh b/src/arch/power/insts/integer.hh index 6d39a5fed..59566e88b 100644 --- a/src/arch/power/insts/integer.hh +++ b/src/arch/power/insts/integer.hh @@ -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__ diff --git a/src/arch/power/isa/decoder.isa b/src/arch/power/isa/decoder.isa index 1c67d3aaa..73b0973f7 100644 --- a/src/arch/power/isa/decoder.isa +++ b/src/arch/power/isa/decoder.isa @@ -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; }}); diff --git a/src/arch/power/isa/formats/integer.isa b/src/arch/power/isa/formats/integer.isa index bc52340ec..6f8d03861 100644 --- a/src/arch/power/isa/formats/integer.isa +++ b/src/arch/power/isa/formats/integer.isa @@ -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 +}}; -- 2.30.2