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

import chisel3._
import chisel3.util._
Y
Yinan Xu 已提交
5
import utils._
6
import xiangshan._
7
import xiangshan.backend.decode.DecodeStage
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))
19
  val readRf = Vec(NRIntReadPorts, Flipped(new RfReadPort(XLEN)))
L
LinJiawei 已提交
20
  val jumpPc = Output(UInt(VAddrBits.W))
Y
YikeZhou 已提交
21 22
  // 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 已提交
23
  val redirect = ValidIO(new Redirect)
24 25 26 27
}

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

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

L
LinJiawei 已提交
40
class RedirectGenerator extends XSModule with HasCircularQueuePtrHelper {
L
LinJiawei 已提交
41 42 43 44
  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 已提交
45
    val stage2FtqRead = new FtqRead
L
LinJiawei 已提交
46
    val stage2Redirect = ValidIO(new Redirect)
L
LinJiawei 已提交
47
    val stage3Redirect = ValidIO(new Redirect)
L
LinJiawei 已提交
48 49 50 51
  })
  /*
        LoadQueue  Jump  ALU0  ALU1  ALU2  ALU3   exception    Stage1
          |         |      |    |     |     |         |
L
LinJiawei 已提交
52
          |============= reg & compare =====|         |       ========
L
LinJiawei 已提交
53 54 55 56
                            |                         |
                            |                         |
                            |                         |        Stage2
                            |                         |
L
LinJiawei 已提交
57 58 59 60 61 62 63 64
                    redirect (flush backend)          |
                    |                                 |
               === reg ===                            |       ========
                    |                                 |
                    |----- mux (exception first) -----|        Stage3
                            |
                redirect (send to frontend)
   */
L
LinJiawei 已提交
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
  def selectOlderRedirect(x: Valid[Redirect], y: Valid[Redirect]): Valid[Redirect] = {
    Mux(isAfter(x.bits, y.bits) && y.valid, y, x)
  }
  def selectOlderExuOut(x: Valid[ExuOutput], y: Valid[ExuOutput]): Valid[ExuOutput] = {
    Mux(isAfter(x.bits.redirect, y.bits.redirect) && y.valid, y, x)
  }
  val jumpOut = io.exuMispredict.head
  val oldestAluOut = ParallelOperation(io.exuMispredict.tail, selectOlderExuOut)
  val oldestExuOut = selectOlderExuOut(oldestAluOut, jumpOut) // select between jump and alu

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

  val s1_isJalr = RegEnable(JumpOpType.jumpOpisJalr(jumpOut.bits.uop.ctrl.fuOpType), jumpOut.valid)
  val s1_JalrTarget = RegEnable(jumpOut.bits.redirect.cfiUpdate.target, jumpOut.valid)
  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
  val s2_isJalr = RegEnable(s1_isJalr, s1_redirect_valid_reg)
  val s2_JalrTarget = RegEnable(s1_JalrTarget, s1_redirect_valid_reg)
  val s2_imm12_reg = RegEnable(s1_imm12_reg, s1_redirect_valid_reg)
  val s2_pd = RegEnable(s1_pd, s1_redirect_valid_reg)
  val s2_redirect_bits_reg = Reg(new Redirect)
  val s2_redirect_valid_reg = RegInit(false.B)

  val ftqRead = io.stage2FtqRead.entry
  val pc = GetPcByFtq(ftqRead.ftqPC, s2_redirect_bits_reg.ftqOffset)
  val brTarget = pc + SignExt(s2_imm12_reg, XLEN)
  val isReplay = RedirectLevel.flushItself(s2_redirect_bits_reg.level)
  val target = Mux(isReplay,
    pc, // repaly from itself
    Mux(s2_isJalr,
      s2_JalrTarget, // jalr already save target
      brTarget // branch
    )
  )
  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
  stage3CfiUpdate.specCnt := ftqRead.specCnt
  stage3CfiUpdate.predTaken :=
    ftqRead.cfiIndex.valid && s2_redirect_bits_reg.ftqOffset === ftqRead.cfiIndex.bits
  stage3CfiUpdate.sawNotTakenBranch := VecInit((0 until PredictWidth).map{ i =>
    if(i == 0) false.B else Cat(ftqRead.br_mask.take(i-1)).orR()
  })(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 已提交
139 140
}

Y
Yinan Xu 已提交
141
class CtrlBlock extends XSModule with HasCircularQueuePtrHelper {
142 143 144 145 146 147 148 149
  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 已提交
150 151 152 153 154 155
    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 已提交
156
      val commits = new RoqCommitIO
Y
Yinan Xu 已提交
157 158
      val roqDeqPtr = Output(new RoqPtr)
    }
159 160
  })

L
LinJiawei 已提交
161
  val ftq = Module(new Ftq)
162 163
  val decode = Module(new DecodeStage)
  val rename = Module(new Rename)
164
  val dispatch = Module(new Dispatch)
Y
Yinan Xu 已提交
165 166
  val intBusyTable = Module(new BusyTable(NRIntReadPorts, NRIntWritePorts))
  val fpBusyTable = Module(new BusyTable(NRFpReadPorts, NRFpWritePorts))
L
LinJiawei 已提交
167
  val redirectGen = Module(new RedirectGenerator)
168

L
LinJiawei 已提交
169
  val roqWbSize = NRIntWritePorts + NRFpWritePorts + exuParameters.StuCnt
170 171

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

L
LinJiawei 已提交
173
  val backendRedirect = redirectGen.io.stage2Redirect
L
LinJiawei 已提交
174 175 176 177 178 179 180 181
  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
182

L
LinJiawei 已提交
183 184 185 186 187 188
  ftq.io.enq <> io.frontend.fetchInfo
  for(i <- 0 until CommitWidth){
    ftq.io.roq_commits(i).valid := roq.io.commits.valid(i)
    ftq.io.roq_commits(i).bits := roq.io.commits.info(i)
  }
  ftq.io.redirect <> backendRedirect
L
LinJiawei 已提交
189
  ftq.io.frontendRedirect <> frontendRedirect
L
LinJiawei 已提交
190 191
  ftq.io.exuWriteback <> io.fromIntBlock.exuRedirect

L
LinJiawei 已提交
192 193
  ftq.io.ftqRead(1) <> redirectGen.io.stage2FtqRead
  ftq.io.ftqRead(2) <> DontCare // TODO: read exception pc form here
L
LinJiawei 已提交
194 195

  io.frontend.redirect_cfiUpdate := frontendRedirect
L
LinJiawei 已提交
196
  io.frontend.commit_cfiUpdate := ftq.io.commit_ftqEntry
Y
Yinan Xu 已提交
197

198 199
  decode.io.in <> io.frontend.cfVec

L
LinJiawei 已提交
200 201 202
  val jumpInst = dispatch.io.enqIQCtrl(0).bits
  ftq.io.ftqRead(0).ptr := jumpInst.cf.ftqPtr // jump
  io.toIntBlock.jumpPc := GetPcByFtq(ftq.io.ftqRead(0).entry.ftqPC, jumpInst.cf.ftqOffset)
L
LinJiawei 已提交
203

204 205
  // pipeline between decode and dispatch
  for (i <- 0 until RenameWidth) {
L
LinJiawei 已提交
206 207
    PipelineConnect(decode.io.out(i), rename.io.in(i), rename.io.in(i).ready,
      backendRedirect.valid || frontendRedirect.valid)
208
  }
209

L
LinJiawei 已提交
210
  rename.io.redirect <> backendRedirect
211 212
  rename.io.roqCommits <> roq.io.commits
  rename.io.out <> dispatch.io.fromRename
213
  rename.io.renameBypass <> dispatch.io.renameBypass
214

L
LinJiawei 已提交
215
  dispatch.io.redirect <> backendRedirect
216
  dispatch.io.enqRoq <> roq.io.enq
217
  dispatch.io.enqLsq <> io.toLsBlock.enqLsq
Y
Yinan Xu 已提交
218 219
  dispatch.io.readIntRf <> io.toIntBlock.readRf
  dispatch.io.readFpRf <> io.toFpBlock.readRf
Y
Yinan Xu 已提交
220 221
  dispatch.io.allocPregs.zipWithIndex.foreach { case (preg, i) =>
    intBusyTable.io.allocPregs(i).valid := preg.isInt
222
    fpBusyTable.io.allocPregs(i).valid := preg.isFp
Y
Yinan Xu 已提交
223 224 225
    intBusyTable.io.allocPregs(i).bits := preg.preg
    fpBusyTable.io.allocPregs(i).bits := preg.preg
  }
226
  dispatch.io.numExist <> io.fromIntBlock.numExist ++ io.fromFpBlock.numExist ++ io.fromLsBlock.numExist
Y
Yinan Xu 已提交
227
  dispatch.io.enqIQCtrl <> io.toIntBlock.enqIqCtrl ++ io.toFpBlock.enqIqCtrl ++ io.toLsBlock.enqIqCtrl
228
//  dispatch.io.enqIQData <> io.toIntBlock.enqIqData ++ io.toFpBlock.enqIqData ++ io.toLsBlock.enqIqData
229

L
LinJiawei 已提交
230

L
LinJiawei 已提交
231
  val flush = backendRedirect.valid && RedirectLevel.isUnconditional(backendRedirect.bits.level)
Y
Yinan Xu 已提交
232 233 234
  fpBusyTable.io.flush := flush
  intBusyTable.io.flush := flush
  for((wb, setPhyRegRdy) <- io.fromIntBlock.wbRegs.zip(intBusyTable.io.wbPregs)){
235
    setPhyRegRdy.valid := wb.valid && wb.bits.uop.ctrl.rfWen
Y
Yinan Xu 已提交
236 237 238 239 240 241 242 243 244 245 246
    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
  }
  intBusyTable.io.rfReadAddr <> dispatch.io.readIntRf.map(_.addr)
  intBusyTable.io.pregRdy <> dispatch.io.intPregRdy
  fpBusyTable.io.rfReadAddr <> dispatch.io.readFpRf.map(_.addr)
  fpBusyTable.io.pregRdy <> dispatch.io.fpPregRdy

L
LinJiawei 已提交
247
  roq.io.redirect <> backendRedirect
L
LinJiawei 已提交
248
  roq.io.exeWbResults.zip(
L
LinJiawei 已提交
249 250 251 252
    io.fromIntBlock.wbRegs ++ io.fromFpBlock.wbRegs ++ io.fromLsBlock.stOut
  ).foreach{
    case(x, y) =>
      x.bits := y.bits
L
LinJiawei 已提交
253
      x.valid := y.valid
L
LinJiawei 已提交
254
  }
L
LinJiawei 已提交
255 256 257 258 259

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

261 262 263
  dispatch.io.readPortIndex.intIndex <> io.toIntBlock.readPortIndex
  dispatch.io.readPortIndex.fpIndex <> io.toFpBlock.readPortIndex

Y
Yinan Xu 已提交
264 265
  // roq to int block
  io.roqio.toCSR <> roq.io.csr
266
  io.roqio.exception.valid := roq.io.redirectOut.valid && roq.io.redirectOut.bits.isException()
Y
Yinan Xu 已提交
267
  io.roqio.exception.bits := roq.io.exception
268
  io.roqio.isInterrupt := roq.io.redirectOut.bits.interrupt
Y
Yinan Xu 已提交
269 270 271
  // roq to mem block
  io.roqio.roqDeqPtr := roq.io.roqDeqPtr
  io.roqio.commits := roq.io.commits
272
}