diff --git a/src/arch/power/insts/integer.cc b/src/arch/power/insts/integer.cc index 25c8691d71..61b7f08f22 100644 --- a/src/arch/power/insts/integer.cc +++ b/src/arch/power/insts/integer.cc @@ -117,6 +117,7 @@ IntArithOp::generateDisassembly( { std::stringstream ss; bool printSecondSrc = true; + bool printThirdSrc = false; // Generate the correct mnemonic std::string myMnemonic(mnemonic); @@ -128,6 +129,10 @@ IntArithOp::generateDisassembly( myMnemonic == "subfze" || myMnemonic == "neg") { printSecondSrc = false; + } else if (myMnemonic == "maddhd" || + myMnemonic == "maddhdu" || + myMnemonic == "maddld") { + printThirdSrc = true; } // Additional characters depending on isa bits being set @@ -151,6 +156,12 @@ IntArithOp::generateDisassembly( if (_numSrcRegs > 1 && printSecondSrc) { ss << ", "; printReg(ss, srcRegIdx(1)); + + // Print the third source register + if (_numSrcRegs > 2 && printThirdSrc) { + ss << ", "; + printReg(ss, srcRegIdx(2)); + } } } diff --git a/src/arch/power/insts/integer.hh b/src/arch/power/insts/integer.hh index 95f15983f4..fccb7cfe55 100644 --- a/src/arch/power/insts/integer.hh +++ b/src/arch/power/insts/integer.hh @@ -134,6 +134,52 @@ class IntArithOp : public IntOp { } + /* Compute 128-bit sum of 128-bit to 64-bit unsigned integer addition */ + inline std::tuple + add(uint64_t ralo, uint64_t rahi, uint64_t rb) const + { + uint64_t slo, shi; + #if defined(__SIZEOF_INT128__) + __uint128_t ra = ((__uint128_t)rahi << 64) | ralo; + __uint128_t sum = ra + rb; + slo = sum; + shi = sum >> 64; + #else + shi = rahi + ((ralo + rb) < ralo); + slo = ralo + rb; + #endif + return std::make_tuple(slo, shi); + } + + /* Compute 128-bit sum of 128-bit to 64-bit signed integer addition */ + inline std::tuple + add(uint64_t ralo, int64_t rahi, int64_t rb) const + { + uint64_t slo; + int64_t shi; + #if defined(__SIZEOF_INT128__) + __int128_t ra = ((__int128_t)rahi << 64) | ralo; + __int128_t sum = (__int128_t)ra + rb; + slo = sum; + shi = sum >> 64; + #else + if (rb < 0) { + shi = rahi - 1; + slo = ralo + rb; + if (slo < rb) { + shi++; + } + } else { + shi = rahi; + slo = ralo + rb; + if (slo < rb) { + shi++; + } + } + #endif + return std::make_tuple(slo, shi); + } + /** * Compute 128-bit product of 64-bit unsigned integer multiplication * based on https://stackoverflow.com/a/28904636 @@ -177,6 +223,48 @@ class IntArithOp : public IntOp return std::make_tuple(plo, (int64_t)phi); } + /** + * Compute 128-bit result of 64-bit unsigned integer multiplication + * followed by addition + */ + inline std::tuple + multiplyAdd(uint64_t ra, uint64_t rb, uint64_t rc) const + { + uint64_t rlo, rhi; + #if defined(__SIZEOF_INT128__) + __uint128_t res = ((__uint128_t)ra * rb) + rc; + rlo = res; + rhi = res >> 64; + #else + uint64_t plo, phi; + std::tie(plo, phi) = multiply(ra, rb); + std::tie(rlo, rhi) = add(plo, phi, rc); + #endif + return std::make_tuple(rlo, rhi); + } + + /** + * Compute 128-bit result of 64-bit signed integer multiplication + * followed by addition + */ + inline std::tuple + multiplyAdd(int64_t ra, int64_t rb, int64_t rc) const + { + uint64_t rlo; + int64_t rhi; + #if defined(__SIZEOF_INT128__) + __int128_t res = (__int128_t)ra * rb + rc; + rlo = res; + rhi = res >> 64; + #else + uint64_t plo; + int64_t phi; + std::tie(plo, phi) = multiply(ra, rb); + std::tie(rlo, rhi) = add(plo, phi, rc); + #endif + return std::make_tuple(rlo, rhi); + } + std::string generateDisassembly( Addr pc, const Loader::SymbolTable *symtab) const override; }; diff --git a/src/arch/power/isa/decoder.isa b/src/arch/power/isa/decoder.isa index b4c90fcf79..e8fcb6676b 100644 --- a/src/arch/power/isa/decoder.isa +++ b/src/arch/power/isa/decoder.isa @@ -36,6 +36,31 @@ // decode PO default Unknown::unknown() { + 4: decode VA_XO { + + // Arithmetic instructions that use source registers Ra, Rb and Rc, + // with destination register Rt. + format IntArithOp { + 48: maddhd({{ + int64_t res; + std::tie(std::ignore, res) = multiplyAdd(Ra_sd, Rb_sd, Rc_sd); + Rt = res; + }}); + + 49: maddhdu({{ + uint64_t res; + std::tie(std::ignore, res) = multiplyAdd(Ra, Rb, Rc); + Rt = res; + }}); + + 51: maddld({{ + uint64_t res; + std::tie(res, std::ignore) = multiplyAdd(Ra_sd, Rb_sd, Rc_sd); + Rt = res; + }}); + } + } + format IntImmArithOp { 7: mulli({{ int64_t res = Ra_sd * si; diff --git a/src/arch/power/isa/formats/integer.isa b/src/arch/power/isa/formats/integer.isa index 183c08bdc4..924198dfcf 100644 --- a/src/arch/power/isa/formats/integer.isa +++ b/src/arch/power/isa/formats/integer.isa @@ -290,6 +290,16 @@ def format IntSumOp(src1, src2, ca = {{ 0 }}, computeCA = 0, }}; +// Instructions that use source registers Ra and Rb, with the result +// placed into Rt but do not check for carry, overflow or the Rc bit. +def format IntArithOp(code, inst_flags = []) {{ + + # Generate the class + (header_output, decoder_output, decode_block, exec_output) = \ + GenAluOp(name, Name, 'IntArithOp', code, inst_flags, BasicDecode, + BasicConstructor) +}}; + // Instructions that use source registers Ra and Rb, with the result // placed into Rt. Basically multiply and divide instructions. The