From d5e37b4e9f71b38c16626c038ca9ce41233cf027 Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Sat, 6 Feb 2021 17:21:54 +0530 Subject: [PATCH] arch-power: Add doubleword shift instructions This introduces a new class and a new format for XS form instructions where the shift amount is specified by two fields that must be concatenated and adds the following instructions. * Shift Left Doubleword (sld[.]) * Shift Right Doubleword (srd[.]) * Shift Right Algebraic Doubleword (srad[.]) * Shift Right Algebraic Doubleword Immediate (sradi[.]) * Extend-Sign Word and Shift Left Immediate (extswsli[.]) Change-Id: If51c676009ddafb40f855b66c00eeeffa5d8874c Signed-off-by: Sandipan Das Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/40928 Reviewed-by: Boris Shingarov Maintainer: Boris Shingarov Tested-by: kokoro --- src/arch/power/insts/integer.cc | 62 +++++++++ src/arch/power/insts/integer.hh | 22 +++ src/arch/power/isa/decoder.isa | 185 +++++++++++++++++-------- src/arch/power/isa/formats/integer.isa | 35 +++++ 4 files changed, 243 insertions(+), 61 deletions(-) diff --git a/src/arch/power/insts/integer.cc b/src/arch/power/insts/integer.cc index 2a3ab3130a..484354bf6a 100644 --- a/src/arch/power/insts/integer.cc +++ b/src/arch/power/insts/integer.cc @@ -594,6 +594,68 @@ IntShiftOp::generateDisassembly( } +std::string +IntConcatShiftOp::generateDisassembly( + Addr pc, const Loader::SymbolTable *symtab) const +{ + std::stringstream ss; + bool printSecondSrc = true; + bool printShift = false; + + // Generate the correct mnemonic + std::string myMnemonic(mnemonic); + + // Special cases + if (myMnemonic == "sradi" || + myMnemonic == "extswsli") { + printSecondSrc = false; + printShift = true; + } + + // Additional characters depending on isa bits being set + if (rc) + 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 (rc) { + if (_numSrcRegs > 2) { + ss << ", "; + printReg(ss, srcRegIdx(2)); + } + } else { + if (_numSrcRegs > 1) { + ss << ", "; + printReg(ss, srcRegIdx(1)); + } + } + } + } + + // Print the shift value + if (printShift) + ss << ", " << (int) sh; + + return ss.str(); +} + + std::string IntRotateOp::generateDisassembly( Addr pc, const loader::SymbolTable *symtab) const diff --git a/src/arch/power/insts/integer.hh b/src/arch/power/insts/integer.hh index 7a8c201a34..d655e08b6d 100644 --- a/src/arch/power/insts/integer.hh +++ b/src/arch/power/insts/integer.hh @@ -600,6 +600,28 @@ class IntShiftOp : public IntOp }; +/** + * Class for integer shift operations with a shift value obtained from + * a register or by concatenating immediates. + */ +class IntConcatShiftOp : public IntOp +{ + protected: + + uint8_t sh; + + /// Constructor + IntConcatShiftOp(const char *mnem, MachInst _machInst, OpClass __opClass) + : IntOp(mnem, _machInst, __opClass), + sh((machInst.shn << 5) | machInst.sh) + { + } + + std::string generateDisassembly( + Addr pc, const Loader::SymbolTable *symtab) const override; +}; + + /** * Class for integer rotate operations. */ diff --git a/src/arch/power/isa/decoder.isa b/src/arch/power/isa/decoder.isa index 2db66b6949..2a21a48de8 100644 --- a/src/arch/power/isa/decoder.isa +++ b/src/arch/power/isa/decoder.isa @@ -250,10 +250,19 @@ decode PO default Unknown::unknown() { Ra = res; }}); - format IntLogicOp { - 26: cntlzw({{ Ra = findLeadingZeros(Rs_uw); }}, true); - 28: and({{ Ra = Rs & Rb; }}, true); - } + 26: IntLogicOp::cntlzw({{ Ra = findLeadingZeros(Rs_uw); }}, true); + + 27: IntConcatShiftOp::sld({{ + int64_t shift = Rb_sd; + uint64_t res = Rs & ~((shift << 57) >> 63); + if (shift != 0) { + shift = bits(shift, 5, 0); + res = res << shift; + } + Ra = res; + }}); + + 28: IntLogicOp::and({{ Ra = Rs & Rb; }}, true); 32: IntCompOp::cmpl({{ if (l) @@ -512,6 +521,17 @@ decode PO default Unknown::unknown() { }}); 538: IntLogicOp::cnttzw({{ Ra = findTrailingZeros(Rs_uw); }}, true); + + 539: IntConcatShiftOp::srd({{ + int64_t shift = Rb_sd; + uint64_t res = Rs & ~((shift << 57) >> 63); + if (shift != 0) { + shift = bits(shift, 5, 0); + res = res >> shift; + } + Ra = res; + }}); + 567: LoadIndexUpdateOp::lfsux({{ Ft_sf = Mem_sf; }}); 570: IntLogicOp::cnttzd({{ Ra = findTrailingZeros(Rs); }}, true); 598: MiscOp::sync({{ }}, [ IsReadBarrier, IsWriteBarrier ]); @@ -590,40 +610,57 @@ decode PO default Unknown::unknown() { 790: LoadIndexOp::lhbrx({{ Rt = swap_byte(Mem_uh); }}); - format IntShiftOp { - 792: sraw({{ - int32_t src = Rs_sw; - uint32_t shift = Rb_uw; - int64_t res; - if (bits(shift, 5)) { - res = src >> 31; - if (res != 0) { - setCA = true; - } - } else { - if (shift != 0) { - shift = bits(shift, 4, 0); - res = src >> shift; - setCA = src < 0 && (src & mask(shift)) != 0; - } else { - res = src; - } + 792: IntShiftOp::sraw({{ + int32_t src = Rs_sw; + uint32_t shift = Rb_uw; + int64_t res; + if (bits(shift, 5)) { + res = src >> 31; + if (res != 0) { + setCA = true; } - Ra = res; - }}, true); - - 824: srawi({{ - int32_t src = Rs_sw; - int64_t res; - if (sh) { - res = src >> sh; - setCA = src < 0 && (src & mask(sh)) != 0; + } else { + if (shift != 0) { + shift = bits(shift, 4, 0); + res = src >> shift; + setCA = src < 0 && (src & mask(shift)) != 0; } else { res = src; } - Ra = res; - }}, true); - } + } + Ra = res; + }}, true); + + 794: IntConcatShiftOp::srad({{ + int64_t src = Rs_sd; + uint64_t shift = Rb; + int64_t res; + if (bits(shift, 6)) { + res = src >> 63; + setCA = res != 0; + } else { + if (shift != 0) { + shift = shift & 0x3f; + res = src >> shift; + setCA = src < 0 && (src & mask(shift)) != 0; + } else { + res = src; + } + } + Ra = res; + }}, true); + + 824: IntShiftOp::srawi({{ + int32_t src = Rs_sw; + int64_t res; + if (sh) { + res = src >> sh; + setCA = src < 0 && (src & mask(sh)) != 0; + } else { + res = src; + } + Ra = res; + }}, true); 854: MiscOp::eieio({{ }}, [ IsReadBarrier, IsWriteBarrier ]); 855: LoadIndexOp::lfiwax({{ Ft_uw = Mem; }}); @@ -810,38 +847,64 @@ decode PO default Unknown::unknown() { }}, true); } - default: decode XFX_XO { - format IntOp { - 19: mfcr({{ Rt = CR; }}); - - 144: mtcrf({{ - uint32_t mask = 0; - for (int i = 0; i < 8; ++i) { - if (((FXM >> i) & 0x1) == 0x1) { - mask |= 0xf << (4 * i); + // These instructions are of XS form and use bits 21 - 29 as XO. + default: decode XS_XO { + format IntConcatShiftOp { + 413: sradi({{ + int64_t src = Rs_sd; + if (sh != 0) { + Ra = src >> sh; + if (src < 0 && (src & mask(sh))) { + setCA = true; } + } else { + Ra = src; + } + }}, true); + + 445: extswsli({{ + int64_t src = Rs_sw; + if (sh != 0) { + Ra = src << sh; + } else { + Ra = src; } - CR = (Rs & mask) | (CR & ~mask); }}); + } - 339: decode SPR { - 0x20: mfxer({{ Rt = XER; }}); - 0x100: mflr({{ Rt = LR; }}); - 0x120: mfctr({{ Rt = CTR; }}); - 0x1f9: mftar({{ Rt = TAR; }}); + default: decode XFX_XO { + format IntOp { + 19: mfcr({{ Rt = CR; }}); + + 144: mtcrf({{ + uint32_t mask = 0; + for (int i = 0; i < 8; ++i) { + if (((FXM >> i) & 0x1) == 0x1) { + mask |= 0xf << (4 * i); + } + } + CR = (Rs & mask) | (CR & ~mask); + }}); + + 339: decode SPR { + 0x20: mfxer({{ Rt = XER; }}); + 0x100: mflr({{ Rt = LR; }}); + 0x120: mfctr({{ Rt = CTR; }}); + 0x1f9: mftar({{ Rt = TAR; }}); + } + + 467: decode SPR { + 0x20: mtxer({{ XER = Rs; }}); + 0x100: mtlr({{ LR = Rs; }}); + 0x120: mtctr({{ CTR = Rs; }}); + 0x1f9: mttar({{ TAR = Rs; }}); + } + + 512: mcrxr({{ + CR = insertCRField(CR, BF, XER<31:28>); + XER = XER<27:0>; + }}); } - - 467: decode SPR { - 0x20: mtxer({{ XER = Rs; }}); - 0x100: mtlr({{ LR = Rs; }}); - 0x120: mtctr({{ CTR = Rs; }}); - 0x1f9: mttar({{ TAR = Rs; }}); - } - - 512: mcrxr({{ - CR = insertCRField(CR, BF, XER<31:28>); - XER = XER<27:0>; - }}); } } } diff --git a/src/arch/power/isa/formats/integer.isa b/src/arch/power/isa/formats/integer.isa index d8abd5af95..3cef9ccbb1 100644 --- a/src/arch/power/isa/formats/integer.isa +++ b/src/arch/power/isa/formats/integer.isa @@ -453,6 +453,41 @@ def format IntArithCheckRcOp(code, computeOV = 0, inst_flags = []) {{ }}; +// Integer instructions that also perform shift operations. Everything +// is same as above except if the shift value is not obtained from a +// register, two immediates need to be concatenated to get the final +// shift value. +def format IntConcatShiftOp(code, computeCA = 0, inst_flags = []) {{ + dict = {'result':'Ra'} + + # Add code to setup variables and access XER if necessary + code = 'GEM5_VAR_USED bool setCA = false;\n' + code + + # Code when Rc is set + code_rc1 = readXERCode + code + computeCR0Code % dict + + # Add code for calculating the carry, if needed + if computeCA: + code = readXERCode + code + setCACode + setXERCode + code_rc1 += setCACode + setXERCode + + # Generate the first class + (header_output, decoder_output, decode_block, exec_output) = \ + GenAluOp(name, Name, 'IntConcatShiftOp', code, inst_flags, + CheckRcDecode, BasicConstructor) + + # Generate the second class + (header_output_rc1, decoder_output_rc1, _, exec_output_rc1) = \ + GenAluOp(name, Name + 'RcSet', 'IntConcatShiftOp', code_rc1, + inst_flags, CheckRcDecode, BasicConstructor) + + # Finally, add to the other outputs + header_output += header_output_rc1 + decoder_output += decoder_output_rc1 + exec_output += exec_output_rc1 +}}; + + // 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.