From 76ccfdefa23a72a0f4c90e6810b1c042c537fc51 Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Thu, 7 Jun 2018 12:21:13 +0530 Subject: [PATCH] arch-power: Add fixed-point doubleword arithmetic divide extended instructions This adds the following arithmetic instructions: * Divide Doubleword Extended (divde[o][.]) * Divide Doubleword Extended Unsigned (divdeu[o][.]) Change-Id: I535605fa6d32153054d259bcb14b952a26a1372a Signed-off-by: Sandipan Das --- src/arch/power/insts/integer.hh | 89 +++++++++++++++++++++++++++++++++ src/arch/power/isa/decoder.isa | 26 ++++++++++ 2 files changed, 115 insertions(+) diff --git a/src/arch/power/insts/integer.hh b/src/arch/power/insts/integer.hh index 538750215..61602af96 100644 --- a/src/arch/power/insts/integer.hh +++ b/src/arch/power/insts/integer.hh @@ -278,6 +278,95 @@ class IntArithOp : public IntOp return std::make_tuple(rlo, rhi); } + /* Compute overflow, 64-bit quotient and 64-bit remainder of + 128-bit by 64-bit unsigned integer division */ + inline std::tuple + divide(uint64_t ralo, uint64_t rahi, uint64_t rb) const + { + bool ov; + uint64_t q, r; + #if defined(__SIZEOF_INT128__) + if (rb == 0) { + ov = true; + } else { + __uint128_t ra = ((__uint128_t)rahi << 64) | ralo; + __uint128_t res = ra / rb; + q = res; + r = ra % rb; + ov = res > UINT64_MAX; + } + #else + uint64_t c = 0; + + if (rb == 0) { + ov = true; + } else if (rahi == 0) { + q = ralo / rb; + r = ralo % rb; + ov = false; + } else if (rahi >= rb) { + ov = true; + } else { + for (int i = 0; i < 64; ++i) { + c = rahi >> 63; + rahi = (rahi << 1) | (ralo >> 63); + if (c || (rahi >= rb)) { + rahi -= rb; + c = 1; + } else { + c = 0; + } + ralo = (ralo << 1) | c; + } + q = ralo; + r = rahi; + ov = false; + } + #endif + return std::make_tuple(ov, q, r); + } + + /* Compute overflow, 64-bit quotient and 64-bit remainder of + 128-bit by 64-bit signed integer division */ + inline std::tuple + divide(uint64_t ralo, int64_t rahi, int64_t rb) const + { + bool ov; + int64_t q, r; + #if defined(__SIZEOF_INT128__) + if (rb == 0) { + ov = true; + } else { + __int128_t ra = ((__int128_t)rahi << 64) | ralo; + __int128_t res = ra / rb; + q = res; + r = ra % rb; + ov = res != q; + } + #else + bool raneg = rahi < 0; + bool rbneg = rb < 0; + + if (raneg) { + ralo = ~(ralo); + rahi = ~(rahi); + if (ralo == -1ULL) { + ralo = 0; + rahi++; + } else { + ralo++; + } + } + + if (rbneg) rb = -rb; + std::tie(ov, q, r) = divide(ralo, (uint64_t)rahi, (uint64_t)rb); + if (raneg ^ rbneg) q = -q; + if (raneg) r = -r; + if (!ov) ov = ((q < 0) ^ (raneg ^ rbneg)); + #endif + return std::make_tuple(ov, q, r); + } + std::string generateDisassembly( Addr pc, const SymbolTable *symtab) const override; }; diff --git a/src/arch/power/isa/decoder.isa b/src/arch/power/isa/decoder.isa index 3f0949cd7..8a3da348f 100644 --- a/src/arch/power/isa/decoder.isa +++ b/src/arch/power/isa/decoder.isa @@ -743,6 +743,32 @@ decode PO default Unknown::unknown() { } }}, true); + + 425: divde({{ + int64_t src1 = Ra_sd; + int64_t src2 = Rb_sd; + int64_t res; + std::tie(setOV, res, std::ignore) = divide(0, src1, src2); + if (!setOV) { + Rt = res; + } else { + Rt = 0; + } + }}, + true); + + 393: divdeu({{ + uint64_t src1 = Ra; + uint64_t src2 = Rb; + uint64_t res; + std::tie(setOV, res, std::ignore) = divide(0, src1, src2); + if (!setOV) { + Rt = res; + } else { + Rt = 0; + } + }}, + true); } default: decode XFX_XO { -- 2.30.2