1
0
Fork 0
rocket-chip/src/main/scala/rocket/Multiplier.scala

174 lines
6.5 KiB
Scala
Raw Normal View History

// See LICENSE.Berkeley for license details.
// See LICENSE.SiFive for license details.
2014-09-13 03:06:41 +02:00
package freechips.rocketchip.rocket
import Chisel._
import Chisel.ImplicitConversions._
import freechips.rocketchip.util._
import ALU._
2015-10-06 06:48:05 +02:00
class MultiplierReq(dataBits: Int, tagBits: Int) extends Bundle {
val fn = Bits(width = SZ_ALU_FN)
val dw = Bits(width = SZ_DW)
2015-10-06 06:48:05 +02:00
val in1 = Bits(width = dataBits)
val in2 = Bits(width = dataBits)
val tag = UInt(width = tagBits)
override def cloneType = new MultiplierReq(dataBits, tagBits).asInstanceOf[this.type]
}
2015-10-06 06:48:05 +02:00
class MultiplierResp(dataBits: Int, tagBits: Int) extends Bundle {
val data = Bits(width = dataBits)
val tag = UInt(width = tagBits)
override def cloneType = new MultiplierResp(dataBits, tagBits).asInstanceOf[this.type]
}
2015-10-06 06:48:05 +02:00
class MultiplierIO(dataBits: Int, tagBits: Int) extends Bundle {
val req = Decoupled(new MultiplierReq(dataBits, tagBits)).flip
val kill = Bool(INPUT)
2015-10-06 06:48:05 +02:00
val resp = Decoupled(new MultiplierResp(dataBits, tagBits))
}
Heterogeneous Tiles (#550) Fundamental new features: * Added tile package: This package is intended to hold components re-usable across different types of tile. Will be the future location of TL2-RoCC accelerators and new diplomatic versions of intra-tile interfaces. * Adopted [ModuleName]Params convention: Code base was very inconsistent about what to name case classes that provide parameters to modules. Settled on calling them [ModuleName]Params to distinguish them from config.Parameters and config.Config. So far applied mostly only to case classes defined within rocket and tile. * Defined RocketTileParams: A nested case class containing case classes for all the components of a tile (L1 caches and core). Allows all such parameters to vary per-tile. * Defined RocketCoreParams: All the parameters that can be varied per-core. * Defined L1CacheParams: A trait defining the parameters common to L1 caches, made concrete in different derived case classes. * Defined RocketTilesKey: A sequence of RocketTileParams, one for every tile to be created. * Provided HeterogeneousDualCoreConfig: An example of making a heterogeneous chip with two cores, one big and one little. * Changes to legacy code: ReplacementPolicy moved to package util. L1Metadata moved to package tile. Legacy L2 cache agent removed because it can no longer share the metadata array implementation with the L1. Legacy GroundTests on life support. Additional changes that got rolled in along the way: * rocket: Fix critical path through BTB for I$ index bits > pgIdxBits * coreplex: tiles connected via :=* * groundtest: updated to use TileParams * tilelink: cache cork requirements are relaxed to allow more cacheless masters
2017-02-09 22:59:09 +01:00
case class MulDivParams(
mulUnroll: Int = 1,
2017-03-07 00:03:14 +01:00
divUnroll: Int = 1,
mulEarlyOut: Boolean = false,
divEarlyOut: Boolean = false
)
Heterogeneous Tiles (#550) Fundamental new features: * Added tile package: This package is intended to hold components re-usable across different types of tile. Will be the future location of TL2-RoCC accelerators and new diplomatic versions of intra-tile interfaces. * Adopted [ModuleName]Params convention: Code base was very inconsistent about what to name case classes that provide parameters to modules. Settled on calling them [ModuleName]Params to distinguish them from config.Parameters and config.Config. So far applied mostly only to case classes defined within rocket and tile. * Defined RocketTileParams: A nested case class containing case classes for all the components of a tile (L1 caches and core). Allows all such parameters to vary per-tile. * Defined RocketCoreParams: All the parameters that can be varied per-core. * Defined L1CacheParams: A trait defining the parameters common to L1 caches, made concrete in different derived case classes. * Defined RocketTilesKey: A sequence of RocketTileParams, one for every tile to be created. * Provided HeterogeneousDualCoreConfig: An example of making a heterogeneous chip with two cores, one big and one little. * Changes to legacy code: ReplacementPolicy moved to package util. L1Metadata moved to package tile. Legacy L2 cache agent removed because it can no longer share the metadata array implementation with the L1. Legacy GroundTests on life support. Additional changes that got rolled in along the way: * rocket: Fix critical path through BTB for I$ index bits > pgIdxBits * coreplex: tiles connected via :=* * groundtest: updated to use TileParams * tilelink: cache cork requirements are relaxed to allow more cacheless masters
2017-02-09 22:59:09 +01:00
class MulDiv(cfg: MulDivParams, width: Int, nXpr: Int = 32) extends Module {
2015-10-06 06:48:05 +02:00
val io = new MultiplierIO(width, log2Up(nXpr))
2014-01-14 06:37:16 +01:00
val w = io.req.bits.in1.getWidth
val mulw = (w + cfg.mulUnroll - 1) / cfg.mulUnroll * cfg.mulUnroll
val fastMulW = w/2 > cfg.mulUnroll && w % (2*cfg.mulUnroll) == 0
2014-01-14 06:37:16 +01:00
val s_ready :: s_neg_inputs :: s_mul :: s_div :: s_dummy :: s_neg_output :: s_done_mul :: s_done_div :: Nil = Enum(UInt(), 8)
2014-01-14 06:37:16 +01:00
val state = Reg(init=s_ready)
val req = Reg(io.req.bits)
2017-03-07 00:03:14 +01:00
val count = Reg(UInt(width = log2Ceil((w/cfg.divUnroll + 1) max (w/cfg.mulUnroll))))
2014-01-14 06:37:16 +01:00
val neg_out = Reg(Bool())
val isHi = Reg(Bool())
val resHi = Reg(Bool())
2014-01-14 06:37:16 +01:00
val divisor = Reg(Bits(width = w+1)) // div only needs w bits
val remainder = Reg(Bits(width = 2*mulw+2)) // div only needs 2*w+1 bits
2011-12-20 13:18:28 +01:00
2014-01-14 06:37:16 +01:00
val cmdMul :: cmdHi :: lhsSigned :: rhsSigned :: Nil =
DecodeLogic(io.req.bits.fn, List(X, X, X, X), List(
FN_DIV -> List(N, N, Y, Y),
FN_REM -> List(N, Y, Y, Y),
FN_DIVU -> List(N, N, N, N),
FN_REMU -> List(N, Y, N, N),
FN_MUL -> List(Y, N, X, X),
FN_MULH -> List(Y, Y, Y, Y),
FN_MULHU -> List(Y, Y, N, N),
FN_MULHSU -> List(Y, Y, Y, N))).map(_ toBool)
2011-12-17 16:20:00 +01:00
require(w == 32 || w == 64)
def halfWidth(req: MultiplierReq) = Bool(w > 32) && req.dw === DW_32
def sext(x: Bits, halfW: Bool, signed: Bool) = {
val sign = signed && Mux(halfW, x(w/2-1), x(w-1))
val hi = Mux(halfW, Fill(w/2, sign), x(w-1,w/2))
2014-01-14 06:37:16 +01:00
(Cat(hi, x(w/2-1,0)), sign)
}
val (lhs_in, lhs_sign) = sext(io.req.bits.in1, halfWidth(io.req.bits), lhsSigned)
val (rhs_in, rhs_sign) = sext(io.req.bits.in2, halfWidth(io.req.bits), rhsSigned)
2014-01-14 06:37:16 +01:00
2017-03-07 00:03:14 +01:00
val subtractor = remainder(2*w,w) - divisor
val result = Mux(resHi, remainder(2*w, w+1), remainder(w-1, 0))
val negated_remainder = -result
2014-01-14 06:37:16 +01:00
when (state === s_neg_inputs) {
when (remainder(w-1)) {
2014-01-14 06:37:16 +01:00
remainder := negated_remainder
}
when (divisor(w-1)) {
2014-01-14 06:37:16 +01:00
divisor := subtractor
}
state := s_div
2014-01-14 06:37:16 +01:00
}
when (state === s_neg_output) {
remainder := negated_remainder
state := s_done_div
resHi := false
2011-12-20 12:49:07 +01:00
}
when (state === s_mul) {
2014-01-14 06:37:16 +01:00
val mulReg = Cat(remainder(2*mulw+1,w+1),remainder(w-1,0))
val mplierSign = remainder(w)
2014-01-14 06:37:16 +01:00
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 = (SInt(BigInt(-1) << mulw) >> (count * cfg.mulUnroll)(log2Up(mulw)-1,0))(mulw-1,0)
val eOut = Bool(cfg.mulEarlyOut) && count =/= mulw/cfg.mulUnroll-1 && count =/= 0 &&
!isHi && (mplier & ~eOutMask) === UInt(0)
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))
2014-01-14 06:37:16 +01:00
count := count + 1
when (eOut || count === mulw/cfg.mulUnroll-1) {
state := s_done_mul
resHi := isHi
2014-01-14 06:37:16 +01:00
}
}
when (state === s_div) {
2017-03-07 00:03:14 +01:00
val unrolls = ((0 until cfg.divUnroll) scanLeft remainder) { case (rem, i) =>
// the special case for iteration 0 is to save HW, not for correctness
val difference = if (i == 0) subtractor else rem(2*w,w) - divisor(w-1,0)
val less = difference(w)
Cat(Mux(less, rem(2*w-1,w), difference(w-1,0)), rem(w-1,0), !less)
} tail
remainder := unrolls.last
when (count === w/cfg.divUnroll) {
state := Mux(neg_out, s_neg_output, s_done_div)
resHi := isHi
2017-03-07 00:03:14 +01:00
if (w % cfg.divUnroll < cfg.divUnroll - 1)
remainder := unrolls(w % cfg.divUnroll)
2014-01-14 06:37:16 +01:00
}
count := count + 1
2011-12-20 12:49:07 +01:00
2017-03-07 00:03:14 +01:00
val divby0 = count === 0 && !subtractor(w)
if (cfg.divEarlyOut) {
val divisorMSB = Log2(divisor(w-1,0), w)
val dividendMSB = Log2(remainder(w-1,0), w)
val eOutPos = UInt(w-1) + divisorMSB - dividendMSB
val eOutZero = divisorMSB > dividendMSB
val eOut = count === 0 && !divby0 && (eOutPos >= cfg.divUnroll || eOutZero)
when (eOut) {
val inc = Mux(eOutZero, UInt(w-1), eOutPos) >> log2Floor(cfg.divUnroll)
val shift = inc << log2Floor(cfg.divUnroll)
remainder := remainder(w-1,0) << shift
count := inc
}
2012-10-10 03:29:50 +02:00
}
2017-03-07 00:03:14 +01:00
when (divby0 && !isHi) { neg_out := false }
2014-01-14 06:37:16 +01:00
}
when (io.resp.fire() || io.kill) {
state := s_ready
}
when (io.req.fire()) {
state := Mux(cmdMul, s_mul, Mux(lhs_sign || rhs_sign, s_neg_inputs, s_div))
2014-01-14 06:37:16 +01:00
isHi := cmdHi
resHi := false
count := Mux[UInt](Bool(fastMulW) && cmdMul && halfWidth(io.req.bits), w/cfg.mulUnroll/2, 0)
neg_out := Mux(cmdHi, lhs_sign, lhs_sign =/= rhs_sign)
2014-01-14 06:37:16 +01:00
divisor := Cat(rhs_sign, rhs_in)
remainder := lhs_in
req := io.req.bits
2011-12-20 12:49:07 +01:00
}
val outMul = (state & (s_done_mul ^ s_done_div)) === (s_done_mul & ~s_done_div)
val loOut = Mux(Bool(fastMulW) && halfWidth(req) && outMul, result(w-1,w/2), result(w/2-1,0))
val hiOut = Mux(halfWidth(req), Fill(w/2, loOut(w/2-1)), result(w-1,w/2))
io.resp.bits <> req
io.resp.bits.data := Cat(hiOut, loOut)
io.resp.valid := (state === s_done_mul || state === s_done_div)
2014-01-14 06:37:16 +01:00
io.req.ready := state === s_ready
}