return ss.str();
}
+
+string
+IntConcatRotateOp::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+{
+ stringstream ss;
+ bool printSecondSrc = false;
+ bool printShift = true;
+ bool printMaskBeg = true;
+
+ // Generate the correct mnemonic
+ 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();
+}
Addr pc, const 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 SymbolTable *symtab) const override;
+};
+
} // namespace PowerISA
#endif //__ARCH_POWER_INSTS_INTEGER_HH__
}
}
+ // 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; }});
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
+}};