Skip to content

Commit

Permalink
rs,bypass: add left and right bypass strategy (#971)
Browse files Browse the repository at this point in the history
* rs,bypass: remove optBuf for valid bits

* rs,bypass: add left and right bypass strategy

This commit adds another bypass network implementation to optimize timing of the first stage of function units.

In BypassNetworkLeft, we bypass data at the same cycle that function units write data back. This increases the length of the critical path of the last stage of function units but reduces the length of the critical path of the first stage of function units. Some function units that require a shorter stage zero, like LOAD, may use BypassNetworkLeft.

In this commit, we set all bypass networks to the left style, but we will make it configurable depending on different function units in the future.
  • Loading branch information
poemonsense committed Aug 29, 2021
1 parent 9bc8f3e commit 605f31f
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 36 deletions.
84 changes: 49 additions & 35 deletions src/main/scala/xiangshan/backend/issue/BypassNetwork.scala
Expand Up @@ -23,14 +23,12 @@ import xiangshan._
import utils._


class BypassInfo(numWays: Int, dataBits: Int, optBuf: Boolean = false) extends Bundle {
val validWidth = (if (optBuf) dataBits else 1)

val valid = Vec(numWays, UInt(validWidth.W))
class BypassInfo(numWays: Int, dataBits: Int) extends Bundle {
val valid = Vec(numWays, Bool())
val data = UInt(dataBits.W)

override def cloneType: BypassInfo.this.type =
new BypassInfo(numWays, dataBits, optBuf).asInstanceOf[this.type]
new BypassInfo(numWays, dataBits).asInstanceOf[this.type]
}

class BypassNetworkIO(numWays: Int, numBypass: Int, dataBits: Int) extends Bundle {
Expand All @@ -43,52 +41,68 @@ class BypassNetworkIO(numWays: Int, numBypass: Int, dataBits: Int) extends Bundl
new BypassNetworkIO(numWays, numBypass, dataBits).asInstanceOf[this.type]
}

class BypassNetwork(numWays: Int, numBypass: Int, dataBits: Int, optBuf: Boolean)(implicit p: Parameters)
class BypassNetwork(numWays: Int, numBypass: Int, dataBits: Int)(implicit p: Parameters)
extends XSModule {

val io = IO(new BypassNetworkIO(numWays, numBypass, dataBits))

def doBypass(bypassValid: Seq[Bool], bypassData: Seq[UInt], baseData: UInt, debugIndex: Int = 0): UInt = {
val bypassVec = VecInit(bypassValid)
val target = Mux(bypassVec.asUInt.orR, Mux1H(bypassValid, bypassData), baseData)

XSError(PopCount(bypassVec) > 1.U, p"bypass mask ${Binary(bypassVec.asUInt)} is not one-hot\n")
bypassVec.zipWithIndex.map { case (m, i) =>
XSDebug(bypassVec(i), p"target($debugIndex) bypassed from $i:0x${Hexadecimal(bypassData(i))}\n")
}

target
}

}

// Bypass at the right: RegNext(data) and compute the bypassed data at the next clock cycle
class BypassNetworkRight(numWays: Int, numBypass: Int, dataBits: Int)(implicit p: Parameters)
extends BypassNetwork(numWays, numBypass, dataBits) {

val target_reg = Reg(Vec(numWays, UInt(dataBits.W)))
val bypass_reg = Reg(Vec(numBypass, new BypassInfo(numWays, dataBits, optBuf)))
val bypass_reg = Reg(Vec(numBypass, new BypassInfo(numWays, dataBits)))

when (io.hold) {
target_reg := io.target
if (optBuf) {
bypass_reg.map(_.valid.map(_ := 0.U))
}
else {
bypass_reg.map(_.valid.map(_ := false.B))
}
bypass_reg.map(_.valid.map(_ := false.B))
}.otherwise {
target_reg := io.source
for ((by_reg, by_io) <- bypass_reg.zip(io.bypass)) {
by_reg.data := by_io.data
if (optBuf) {
// duplicate bypass mask to avoid too many FO4s and hurting timing
by_reg.valid := VecInit(by_io.valid.map(v => Cat(Seq.fill(dataBits)(v))))
}
else {
by_reg.valid := by_io.valid
}
by_reg.valid := by_io.valid
}
}

// bypass data to target
for (i <- 0 until numWays) {
if (optBuf) {
val bypassData = VecInit((0 until dataBits).map(j => {
val mask = VecInit(bypass_reg.map(_.valid(i)(j)))
Mux(mask.asUInt.orR, Mux1H(mask, bypass_reg.map(_.data(j))), target_reg(i)(j))
})).asUInt
io.target(i) := bypassData
}
else {
val mask = VecInit(bypass_reg.map(_.valid(i).asBool))
io.target(i) := Mux(mask.asUInt.orR, Mux1H(mask, bypass_reg.map(_.data)), target_reg(i))

XSError(PopCount(mask) > 1.U, p"bypass mask ${Binary(mask.asUInt)} is not one-hot\n")
mask.zipWithIndex.map { case (m, j) =>
XSDebug(mask(j), p"target($i) bypassed from $j:0x${Hexadecimal(bypass_reg(j).data)}\n")
}
io.target(i) := doBypass(bypass_reg.map(_.valid(i)), bypass_reg.map(_.data), target_reg(i))
}

}

// Bypass at the left: compute the bypassed data and RegNext(bypassed_data)
class BypassNetworkLeft(numWays: Int, numBypass: Int, dataBits: Int)(implicit p: Parameters)
extends BypassNetwork(numWays, numBypass, dataBits) {

val bypassedData = Reg(io.target.cloneType)

when (!io.hold) {
for ((by, i) <- bypassedData.zipWithIndex) {
by := doBypass(io.bypass.map(_.valid(i)), io.bypass.map(_.data), io.source(i))
}
}

io.target := bypassedData

}

object BypassNetwork {
def apply(numWays: Int, numBypass: Int, dataBits: Int, optFirstStage: Boolean)(implicit p: Parameters) = {
Module(new BypassNetworkLeft(numWays, numBypass, dataBits))
}
}
Expand Up @@ -448,7 +448,7 @@ class ReservationStation(params: RSParams)(implicit p: Parameters) extends XSMod
wakeupBypassMask(j) := VecInit(targetFastWakeupMatch.map(_ (j)))
}

val bypassNetwork = Module(new BypassNetwork(params.numSrc, params.numFastWakeup, params.dataBits, params.optBuf))
val bypassNetwork = BypassNetwork(params.numSrc, params.numFastWakeup, params.dataBits, params.optBuf)
bypassNetwork.io.hold := !io.deq(i).ready
bypassNetwork.io.source := s1_out(i).bits.src.take(params.numSrc)
bypassNetwork.io.bypass.zip(wakeupBypassMask.zip(io.fastDatas)).foreach { case (by, (m, d)) =>
Expand Down

0 comments on commit 605f31f

Please sign in to comment.