FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Rocket-Chipの乗除算器について調べる (2. 負数の扱いに関する調査)

Rocket-Chipの採用している乗算器について少しずつ眺めているが、まだ良く分からないことがある。 負数の扱いについてはどのようになっているのだろう。 負数の乗算については正直あまり知らなかったので、ここで調査してみる。

いくつか検索すると以下のようなサイトが上がってきた。

qiita.com

www.kumikomi.net

この辺を読むと、なるほど負数の乗算というのは難しいのだなとなっているが、これとRocket-ChipのMultiplierの実装の相違がまだ理解できていない。

Rocket-Chipでは、Scalaで乗算器が実装されている。 ここで、第1オペランド(lhs)が負数であればneg_outという信号を有効化している。

   when (io.req.fire()) {
     state := Mux(cmdMul, s_mul, Mux(lhs_sign || rhs_sign, s_neg_inputs, s_div))
     isHi := cmdHi
     resHi := false
     count := (if (fastMulW) Mux[UInt](cmdMul && halfWidth(io.req.bits), w/cfg.mulUnroll/2, 0) else 0)
     neg_out := Mux(cmdHi, lhs_sign, lhs_sign =/= rhs_sign)
     divisor := Cat(rhs_sign, rhs_in)
     remainder := lhs_in
     req := io.req.bits
   }

ここから、ループを回しているのだが、最後の計算をする前に、負数の場合には最上位1ビットを挿入するようになっている。 しかし最初の計算の1ビットはどこで挿入しているんだ?

   if (cfg.mulUnroll != 0) when (state === s_mul) {
     val mulReg = Cat(remainder(2*mulw+1,w+1),remainder(w-1,0))
     val mplierSign = remainder(w)
     val mplier = mulReg(mulw-1,0)
     val accum = mulReg(2*mulw,mulw).asSInt
     val mpcand = divisor.asSInt
     val prod = Cat(mplierSign, mplier(cfg.mulUnroll-1, 0)).asSInt * mpcand + accum
     val nextMulReg = Cat(prod, mplier(mulw-1, cfg.mulUnroll))
     val nextMplierSign = count === mulw/cfg.mulUnroll-2 && neg_out

     val eOutMask = ((BigInt(-1) << mulw).S >> (count * cfg.mulUnroll)(log2Up(mulw)-1,0))(mulw-1,0)
     val eOut = (cfg.mulEarlyOut).B && count =/= mulw/cfg.mulUnroll-1 && count =/= 0 &&
       !isHi && (mplier & ~eOutMask) === 0.U
     val eOutRes = (mulReg >> (mulw - count * cfg.mulUnroll)(log2Up(mulw)-1,0))
     val nextMulReg1 = Cat(nextMulReg(2*mulw,mulw), Mux(eOut, eOutRes, nextMulReg)(mulw-1,0))
     remainder := Cat(nextMulReg1 >> w, nextMplierSign, nextMulReg1(w-1,0))

     count := count + 1
     when (eOut || count === mulw/cfg.mulUnroll-1) {
       state := s_done_mul
       resHi := isHi
     }
   }