CtrlBlock.scala 11.8 KB
Newer Older
1 2 3 4
package xiangshan.backend

import chisel3._
import chisel3.util._
Y
Yinan Xu 已提交
5
import utils._
6
import xiangshan._
L
LinJiawei 已提交
7
import xiangshan.backend.decode.{DecodeStage, ImmUnion}
L
LinJiawei 已提交
8
import xiangshan.backend.rename.{BusyTable, Rename}
9 10
import xiangshan.backend.dispatch.Dispatch
import xiangshan.backend.exu._
11
import xiangshan.backend.exu.Exu.exuConfigs
L
LinJiawei 已提交
12
import xiangshan.backend.ftq.{Ftq, FtqRead, GetPcByFtq}
13
import xiangshan.backend.regfile.RfReadPort
L
LinJiawei 已提交
14
import xiangshan.backend.roq.{Roq, RoqCSRIO, RoqPtr}
Y
Yinan Xu 已提交
15
import xiangshan.mem.LsqEnqIO
16 17 18

class CtrlToIntBlockIO extends XSBundle {
  val enqIqCtrl = Vec(exuParameters.IntExuCnt, DecoupledIO(new MicroOp))
Y
Yinan Xu 已提交
19
  val readRf = Vec(NRIntReadPorts, Output(UInt(PhyRegIdxWidth.W)))
L
LinJiawei 已提交
20
  val jumpPc = Output(UInt(VAddrBits.W))
L
LinJiawei 已提交
21
  val jalr_target = Output(UInt(VAddrBits.W))
Y
YikeZhou 已提交
22 23
  // int block only uses port 0~7
  val readPortIndex = Vec(exuParameters.IntExuCnt, Output(UInt(log2Ceil(8 / 2).W))) // TODO parameterize 8 here
Y
Yinan Xu 已提交
24
  val redirect = ValidIO(new Redirect)
25 26 27 28
}

class CtrlToFpBlockIO extends XSBundle {
  val enqIqCtrl = Vec(exuParameters.FpExuCnt, DecoupledIO(new MicroOp))
Y
Yinan Xu 已提交
29
  val readRf = Vec(NRFpReadPorts, Output(UInt(PhyRegIdxWidth.W)))
Y
YikeZhou 已提交
30 31
  // fp block uses port 0~11
  val readPortIndex = Vec(exuParameters.FpExuCnt, Output(UInt(log2Ceil((NRFpReadPorts - exuParameters.StuCnt) / 3).W)))
Y
Yinan Xu 已提交
32
  val redirect = ValidIO(new Redirect)
33 34 35 36
}

class CtrlToLsBlockIO extends XSBundle {
  val enqIqCtrl = Vec(exuParameters.LsExuCnt, DecoupledIO(new MicroOp))
Y
Yinan Xu 已提交
37
  val enqLsq = Flipped(new LsqEnqIO)
Y
Yinan Xu 已提交
38
  val redirect = ValidIO(new Redirect)
39 40
}

L
LinJiawei 已提交
41
class RedirectGenerator extends XSModule with HasCircularQueuePtrHelper {
L
LinJiawei 已提交
42 43 44 45
  val io = IO(new Bundle() {
    val loadRelay = Flipped(ValidIO(new Redirect))
    val exuMispredict = Vec(exuParameters.JmpCnt + exuParameters.AluCnt, Flipped(ValidIO(new ExuOutput)))
    val roqRedirect = Flipped(ValidIO(new Redirect))
L
LinJiawei 已提交
46
    val stage2FtqRead = new FtqRead
L
LinJiawei 已提交
47
    val stage2Redirect = ValidIO(new Redirect)
L
LinJiawei 已提交
48
    val stage3Redirect = ValidIO(new Redirect)
L
LinJiawei 已提交
49 50 51 52
  })
  /*
        LoadQueue  Jump  ALU0  ALU1  ALU2  ALU3   exception    Stage1
          |         |      |    |     |     |         |
L
LinJiawei 已提交
53
          |============= reg & compare =====|         |       ========
L
LinJiawei 已提交
54 55 56 57
                            |                         |
                            |                         |
                            |                         |        Stage2
                            |                         |
L
LinJiawei 已提交
58 59 60 61 62 63 64 65
                    redirect (flush backend)          |
                    |                                 |
               === reg ===                            |       ========
                    |                                 |
                    |----- mux (exception first) -----|        Stage3
                            |
                redirect (send to frontend)
   */
L
LinJiawei 已提交
66
  def selectOlderRedirect(x: Valid[Redirect], y: Valid[Redirect]): Valid[Redirect] = {
L
LinJiawei 已提交
67 68 69 70 71 72 73
    Mux(x.valid,
      Mux(y.valid,
        Mux(isAfter(x.bits.roqIdx, y.bits.roqIdx), y, x),
        x
      ),
      y
    )
L
LinJiawei 已提交
74
  }
75 76
  def selectOlderExuOutWithFlag(x: Valid[ExuOutput], y: Valid[ExuOutput]): (Valid[ExuOutput], Bool) = {
    val yIsOlder = Mux(x.valid,
L
LinJiawei 已提交
77
      Mux(y.valid,
78 79
        Mux(isAfter(x.bits.redirect.roqIdx, y.bits.redirect.roqIdx), true.B, false.B),
        false.B
L
LinJiawei 已提交
80
      ),
81
      true.B
L
LinJiawei 已提交
82
    )
83 84 85 86 87
    val sel = Mux(yIsOlder, y, x)
    (sel, yIsOlder)
  }
  def selectOlderExuOut(x: Valid[ExuOutput], y: Valid[ExuOutput]): Valid[ExuOutput] = {
    selectOlderExuOutWithFlag(x, y)._1
L
LinJiawei 已提交
88 89 90
  }
  val jumpOut = io.exuMispredict.head
  val oldestAluOut = ParallelOperation(io.exuMispredict.tail, selectOlderExuOut)
91
  val (oldestExuOut, jumpIsOlder) = selectOlderExuOutWithFlag(oldestAluOut, jumpOut) // select between jump and alu
L
LinJiawei 已提交
92 93 94 95 96 97 98 99

  val oldestMispredict = selectOlderRedirect(io.loadRelay, {
    val redirect = Wire(Valid(new Redirect))
    redirect.valid := oldestExuOut.valid
    redirect.bits := oldestExuOut.bits.redirect
    redirect
  })

100 101
  XSDebug(oldestExuOut.valid, p"exuMispredict: ${Binary(Cat(io.exuMispredict.map(_.valid)))}\n")

102
  val s1_isJump = RegNext(jumpIsOlder, init = false.B)
L
LinJiawei 已提交
103
  val s1_jumpTarget = RegEnable(jumpOut.bits.redirect.cfiUpdate.target, jumpOut.valid)
L
LinJiawei 已提交
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
  val s1_imm12_reg = RegEnable(oldestExuOut.bits.uop.ctrl.imm(11, 0), oldestExuOut.valid)
  val s1_pd = RegEnable(oldestExuOut.bits.uop.cf.pd, oldestExuOut.valid)
  val s1_redirect_bits_reg = Reg(new Redirect)
  val s1_redirect_valid_reg = RegInit(false.B)

  // stage1 -> stage2
  when(oldestMispredict.valid && !oldestMispredict.bits.roqIdx.needFlush(io.stage2Redirect)){
    s1_redirect_bits_reg := oldestMispredict.bits
    s1_redirect_valid_reg := true.B
  }.otherwise({
    s1_redirect_valid_reg := false.B
  })
  io.stage2Redirect.valid := s1_redirect_valid_reg
  io.stage2Redirect.bits := s1_redirect_bits_reg
  io.stage2Redirect.bits.cfiUpdate := DontCare
  // at stage2, we read ftq to get pc
  io.stage2FtqRead.ptr := s1_redirect_bits_reg.ftqIdx

  // stage3, calculate redirect target
L
LinJiawei 已提交
123 124
  val s2_isJump = RegNext(s1_isJump)
  val s2_jumpTarget = RegEnable(s1_jumpTarget, s1_redirect_valid_reg)
L
LinJiawei 已提交
125 126
  val s2_imm12_reg = RegEnable(s1_imm12_reg, s1_redirect_valid_reg)
  val s2_pd = RegEnable(s1_pd, s1_redirect_valid_reg)
L
LinJiawei 已提交
127 128
  val s2_redirect_bits_reg = RegEnable(s1_redirect_bits_reg, enable = s1_redirect_valid_reg)
  val s2_redirect_valid_reg = RegNext(s1_redirect_valid_reg, init = false.B)
L
LinJiawei 已提交
129 130

  val ftqRead = io.stage2FtqRead.entry
L
LinJiawei 已提交
131
  val pc = GetPcByFtq(ftqRead.ftqPC, s2_redirect_bits_reg.ftqOffset, ftqRead.hasLastPrev)
L
LinJiawei 已提交
132
  val brTarget = pc + SignExt(ImmUnion.B.toImm32(s2_imm12_reg), XLEN)
L
LinJiawei 已提交
133
  val snpc = pc + Mux(s2_pd.isRVC, 2.U, 4.U)
L
LinJiawei 已提交
134 135 136
  val isReplay = RedirectLevel.flushItself(s2_redirect_bits_reg.level)
  val target = Mux(isReplay,
    pc, // repaly from itself
L
LinJiawei 已提交
137 138 139
    Mux(s2_redirect_bits_reg.cfiUpdate.taken,
      Mux(s2_isJump, s2_jumpTarget, brTarget),
      snpc
L
LinJiawei 已提交
140 141 142 143 144 145 146 147 148 149 150
    )
  )
  io.stage3Redirect.valid := s2_redirect_valid_reg
  io.stage3Redirect.bits := s2_redirect_bits_reg
  val stage3CfiUpdate = io.stage3Redirect.bits.cfiUpdate
  stage3CfiUpdate.pc := pc
  stage3CfiUpdate.pd := s2_pd
  stage3CfiUpdate.rasSp := ftqRead.rasSp
  stage3CfiUpdate.rasEntry := ftqRead.rasTop
  stage3CfiUpdate.hist := ftqRead.hist
  stage3CfiUpdate.predHist := ftqRead.predHist
L
Lingrui98 已提交
151
  stage3CfiUpdate.specCnt := ftqRead.specCnt(s2_redirect_bits_reg.ftqOffset)
L
LinJiawei 已提交
152
  stage3CfiUpdate.predTaken := s2_redirect_bits_reg.cfiUpdate.predTaken
L
LinJiawei 已提交
153
  stage3CfiUpdate.sawNotTakenBranch := VecInit((0 until PredictWidth).map{ i =>
L
Lingrui98 已提交
154
    if(i == 0) false.B else Cat(ftqRead.br_mask.take(i)).orR()
L
LinJiawei 已提交
155 156 157 158
  })(s2_redirect_bits_reg.ftqOffset)
  stage3CfiUpdate.target := target
  stage3CfiUpdate.taken := s2_redirect_bits_reg.cfiUpdate.taken
  stage3CfiUpdate.isMisPred := s2_redirect_bits_reg.cfiUpdate.isMisPred
L
LinJiawei 已提交
159 160
}

Y
Yinan Xu 已提交
161
class CtrlBlock extends XSModule with HasCircularQueuePtrHelper {
162 163 164 165 166 167 168 169
  val io = IO(new Bundle {
    val frontend = Flipped(new FrontendToBackendIO)
    val fromIntBlock = Flipped(new IntBlockToCtrlIO)
    val fromFpBlock = Flipped(new FpBlockToCtrlIO)
    val fromLsBlock = Flipped(new LsBlockToCtrlIO)
    val toIntBlock = new CtrlToIntBlockIO
    val toFpBlock = new CtrlToFpBlockIO
    val toLsBlock = new CtrlToLsBlockIO
Y
Yinan Xu 已提交
170 171 172 173 174 175
    val roqio = new Bundle {
      // to int block
      val toCSR = new RoqCSRIO
      val exception = ValidIO(new MicroOp)
      val isInterrupt = Output(Bool())
      // to mem block
Y
Yinan Xu 已提交
176
      val commits = new RoqCommitIO
Y
Yinan Xu 已提交
177 178
      val roqDeqPtr = Output(new RoqPtr)
    }
179 180
  })

L
LinJiawei 已提交
181
  val ftq = Module(new Ftq)
182 183
  val decode = Module(new DecodeStage)
  val rename = Module(new Rename)
184
  val dispatch = Module(new Dispatch)
Y
Yinan Xu 已提交
185 186
  val intBusyTable = Module(new BusyTable(NRIntReadPorts, NRIntWritePorts))
  val fpBusyTable = Module(new BusyTable(NRFpReadPorts, NRFpWritePorts))
L
LinJiawei 已提交
187
  val redirectGen = Module(new RedirectGenerator)
188

L
LinJiawei 已提交
189
  val roqWbSize = NRIntWritePorts + NRFpWritePorts + exuParameters.StuCnt
190 191

  val roq = Module(new Roq(roqWbSize))
192

L
LinJiawei 已提交
193
  val backendRedirect = redirectGen.io.stage2Redirect
L
LinJiawei 已提交
194 195 196 197 198 199 200 201
  val frontendRedirect = redirectGen.io.stage3Redirect

  redirectGen.io.exuMispredict.zip(io.fromIntBlock.exuRedirect).map({case (x, y) =>
    x.valid := y.valid && y.bits.redirect.cfiUpdate.isMisPred
    x.bits := y.bits
  })
  redirectGen.io.loadRelay := io.fromLsBlock.replay
  redirectGen.io.roqRedirect := roq.io.redirectOut
202

L
LinJiawei 已提交
203 204
  ftq.io.enq <> io.frontend.fetchInfo
  for(i <- 0 until CommitWidth){
L
LinJiawei 已提交
205
    ftq.io.roq_commits(i).valid := roq.io.commits.valid(i) && !roq.io.commits.isWalk
L
LinJiawei 已提交
206 207 208
    ftq.io.roq_commits(i).bits := roq.io.commits.info(i)
  }
  ftq.io.redirect <> backendRedirect
L
LinJiawei 已提交
209
  ftq.io.frontendRedirect <> frontendRedirect
L
LinJiawei 已提交
210 211
  ftq.io.exuWriteback <> io.fromIntBlock.exuRedirect

L
LinJiawei 已提交
212 213
  ftq.io.ftqRead(1) <> redirectGen.io.stage2FtqRead
  ftq.io.ftqRead(2) <> DontCare // TODO: read exception pc form here
L
LinJiawei 已提交
214 215

  io.frontend.redirect_cfiUpdate := frontendRedirect
L
LinJiawei 已提交
216
  io.frontend.commit_cfiUpdate := ftq.io.commit_ftqEntry
217 218
  io.frontend.ftqEnqPtr := ftq.io.enqPtr
  io.frontend.ftqLeftOne := ftq.io.leftOne
Y
Yinan Xu 已提交
219

220 221
  decode.io.in <> io.frontend.cfVec

L
LinJiawei 已提交
222
  val jumpInst = dispatch.io.enqIQCtrl(0).bits
L
LinJiawei 已提交
223 224
  val ftqOffsetReg = Reg(UInt(log2Up(PredictWidth).W))
  ftqOffsetReg := jumpInst.cf.ftqOffset
L
LinJiawei 已提交
225
  ftq.io.ftqRead(0).ptr := jumpInst.cf.ftqPtr // jump
L
LinJiawei 已提交
226 227 228
  io.toIntBlock.jumpPc := GetPcByFtq(
    ftq.io.ftqRead(0).entry.ftqPC, ftqOffsetReg, ftq.io.ftqRead(0).entry.hasLastPrev
  )
L
LinJiawei 已提交
229
  io.toIntBlock.jalr_target := ftq.io.ftqRead(0).entry.target
L
LinJiawei 已提交
230

231 232
  // pipeline between decode and dispatch
  for (i <- 0 until RenameWidth) {
L
LinJiawei 已提交
233 234
    PipelineConnect(decode.io.out(i), rename.io.in(i), rename.io.in(i).ready,
      backendRedirect.valid || frontendRedirect.valid)
235
  }
236

L
LinJiawei 已提交
237
  rename.io.redirect <> backendRedirect
238 239
  rename.io.roqCommits <> roq.io.commits
  rename.io.out <> dispatch.io.fromRename
240
  rename.io.renameBypass <> dispatch.io.renameBypass
241

L
LinJiawei 已提交
242
  dispatch.io.redirect <> backendRedirect
243
  dispatch.io.enqRoq <> roq.io.enq
244
  dispatch.io.enqLsq <> io.toLsBlock.enqLsq
Y
Yinan Xu 已提交
245 246
  dispatch.io.readIntRf <> io.toIntBlock.readRf
  dispatch.io.readFpRf <> io.toFpBlock.readRf
Y
Yinan Xu 已提交
247 248
  dispatch.io.allocPregs.zipWithIndex.foreach { case (preg, i) =>
    intBusyTable.io.allocPregs(i).valid := preg.isInt
249
    fpBusyTable.io.allocPregs(i).valid := preg.isFp
Y
Yinan Xu 已提交
250 251 252
    intBusyTable.io.allocPregs(i).bits := preg.preg
    fpBusyTable.io.allocPregs(i).bits := preg.preg
  }
253
  dispatch.io.numExist <> io.fromIntBlock.numExist ++ io.fromFpBlock.numExist ++ io.fromLsBlock.numExist
Y
Yinan Xu 已提交
254
  dispatch.io.enqIQCtrl <> io.toIntBlock.enqIqCtrl ++ io.toFpBlock.enqIqCtrl ++ io.toLsBlock.enqIqCtrl
255
//  dispatch.io.enqIQData <> io.toIntBlock.enqIqData ++ io.toFpBlock.enqIqData ++ io.toLsBlock.enqIqData
256

L
LinJiawei 已提交
257

L
LinJiawei 已提交
258
  val flush = backendRedirect.valid && RedirectLevel.isUnconditional(backendRedirect.bits.level)
Y
Yinan Xu 已提交
259 260 261
  fpBusyTable.io.flush := flush
  intBusyTable.io.flush := flush
  for((wb, setPhyRegRdy) <- io.fromIntBlock.wbRegs.zip(intBusyTable.io.wbPregs)){
262
    setPhyRegRdy.valid := wb.valid && wb.bits.uop.ctrl.rfWen
Y
Yinan Xu 已提交
263 264 265 266 267 268
    setPhyRegRdy.bits := wb.bits.uop.pdest
  }
  for((wb, setPhyRegRdy) <- io.fromFpBlock.wbRegs.zip(fpBusyTable.io.wbPregs)){
    setPhyRegRdy.valid := wb.valid && wb.bits.uop.ctrl.fpWen
    setPhyRegRdy.bits := wb.bits.uop.pdest
  }
Y
Yinan Xu 已提交
269 270
  intBusyTable.io.read <> dispatch.io.readIntState
  fpBusyTable.io.read <> dispatch.io.readFpState
Y
Yinan Xu 已提交
271

L
LinJiawei 已提交
272
  roq.io.redirect <> backendRedirect
L
LinJiawei 已提交
273
  roq.io.exeWbResults.zip(
L
LinJiawei 已提交
274 275 276 277
    io.fromIntBlock.wbRegs ++ io.fromFpBlock.wbRegs ++ io.fromLsBlock.stOut
  ).foreach{
    case(x, y) =>
      x.bits := y.bits
L
LinJiawei 已提交
278
      x.valid := y.valid
L
LinJiawei 已提交
279
  }
L
LinJiawei 已提交
280 281 282 283 284

  // TODO: is 'backendRedirect' necesscary?
  io.toIntBlock.redirect <> backendRedirect
  io.toFpBlock.redirect <> backendRedirect
  io.toLsBlock.redirect <> backendRedirect
285

286 287 288
  dispatch.io.readPortIndex.intIndex <> io.toIntBlock.readPortIndex
  dispatch.io.readPortIndex.fpIndex <> io.toFpBlock.readPortIndex

Y
Yinan Xu 已提交
289 290
  // roq to int block
  io.roqio.toCSR <> roq.io.csr
291
  io.roqio.exception.valid := roq.io.redirectOut.valid && roq.io.redirectOut.bits.isException()
Y
Yinan Xu 已提交
292
  io.roqio.exception.bits := roq.io.exception
293
  io.roqio.isInterrupt := roq.io.redirectOut.bits.interrupt
Y
Yinan Xu 已提交
294 295 296
  // roq to mem block
  io.roqio.roqDeqPtr := roq.io.roqDeqPtr
  io.roqio.commits := roq.io.commits
297
}