Rename.scala 13.0 KB
Newer Older
L
Lemover 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/***************************************************************************************
* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
*
* XiangShan is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

16 17
package xiangshan.backend.rename

18
import chipsalliance.rocketchip.config.Parameters
19 20 21
import chisel3._
import chisel3.util._
import xiangshan._
Y
Yinan Xu 已提交
22
import utils._
23
import xiangshan.backend.roq.RoqPtr
24
import xiangshan.backend.dispatch.PreDispatchInfo
25

26
class RenameBypassInfo(implicit p: Parameters) extends XSBundle {
27 28 29 30
  val lsrc1_bypass = MixedVec(List.tabulate(RenameWidth-1)(i => UInt((i+1).W)))
  val lsrc2_bypass = MixedVec(List.tabulate(RenameWidth-1)(i => UInt((i+1).W)))
  val lsrc3_bypass = MixedVec(List.tabulate(RenameWidth-1)(i => UInt((i+1).W)))
  val ldest_bypass = MixedVec(List.tabulate(RenameWidth-1)(i => UInt((i+1).W)))
31 32
  val move_eliminated_src1 = Vec(RenameWidth-1, Bool())
  val move_eliminated_src2 = Vec(RenameWidth-1, Bool())
33 34
}

35
class Rename(implicit p: Parameters) extends XSModule with HasCircularQueuePtrHelper {
36 37
  val io = IO(new Bundle() {
    val redirect = Flipped(ValidIO(new Redirect))
38
    val flush = Input(Bool())
Y
Yinan Xu 已提交
39
    val roqCommits = Flipped(new RoqCommitIO)
40
    // from decode buffer
41
    val in = Vec(RenameWidth, Flipped(DecoupledIO(new CfCtrl)))
42
    // to dispatch1
43
    val out = Vec(RenameWidth, DecoupledIO(new MicroOp))
44
    val renameBypass = Output(new RenameBypassInfo)
45
    val dispatchInfo = Output(new PreDispatchInfo)
46
    val csrCtrl = Flipped(new CustomCSRCtrlIO)
47 48
    val debug_int_rat = Vec(32, Output(UInt(PhyRegIdxWidth.W)))
    val debug_fp_rat = Vec(32, Output(UInt(PhyRegIdxWidth.W)))
49
  })
50

L
LinJiawei 已提交
51 52
  def printRenameInfo(in: DecoupledIO[CfCtrl], out: DecoupledIO[MicroOp]) = {
    XSInfo(
53
      in.valid && in.ready,
L
LinJiawei 已提交
54
      p"pc:${Hexadecimal(in.bits.cf.pc)} in v:${in.valid} in rdy:${in.ready} " +
55 56 57
        p"lsrc(0):${in.bits.ctrl.lsrc(0)} -> psrc(0):${out.bits.psrc(0)} " +
        p"lsrc(1):${in.bits.ctrl.lsrc(1)} -> psrc(1):${out.bits.psrc(1)} " +
        p"lsrc(2):${in.bits.ctrl.lsrc(2)} -> psrc(2):${out.bits.psrc(2)} " +
L
LinJiawei 已提交
58
        p"ldest:${in.bits.ctrl.ldest} -> pdest:${out.bits.pdest} " +
L
LinJiawei 已提交
59
        p"old_pdest:${out.bits.old_pdest} " +
L
LinJiawei 已提交
60
        p"out v:${out.valid} r:${out.ready}\n"
L
LinJiawei 已提交
61 62 63 64 65 66 67
    )
  }

  for((x,y) <- io.in.zip(io.out)){
    printRenameInfo(x, y)
  }

Y
Yinan Xu 已提交
68
  val intFreeList, fpFreeList = Module(new FreeList).io
69
  val intRat = Module(new RenameTable(float = false)).io
Y
Yinan Xu 已提交
70 71
  val fpRat = Module(new RenameTable(float = true)).io
  val allPhyResource = Seq((intRat, intFreeList, false), (fpRat, fpFreeList, true))
72 73
  intRat.debug_rdata <> io.debug_int_rat
  fpRat.debug_rdata <> io.debug_fp_rat
74

Y
Yinan Xu 已提交
75
  allPhyResource.map{ case (rat, freelist, _) =>
76
    rat.redirect := io.redirect.valid
77
    rat.flush := io.flush
Y
Yinan Xu 已提交
78
    rat.walkWen := io.roqCommits.isWalk
79
    freelist.redirect := io.redirect.valid
80
    freelist.flush := io.flush
Y
Yinan Xu 已提交
81 82
    freelist.walk.valid := io.roqCommits.isWalk
  }
83
  val canOut = io.out(0).ready && fpFreeList.req.canAlloc && intFreeList.req.canAlloc && !io.roqCommits.isWalk
84 85 86 87

  def needDestReg[T <: CfCtrl](fp: Boolean, x: T): Bool = {
    {if(fp) x.ctrl.fpWen else x.ctrl.rfWen && (x.ctrl.ldest =/= 0.U)}
  }
Y
Yinan Xu 已提交
88 89 90
  def needDestRegCommit[T <: RoqCommitInfo](fp: Boolean, x: T): Bool = {
    {if(fp) x.fpWen else x.rfWen && (x.ldest =/= 0.U)}
  }
Y
Yinan Xu 已提交
91 92
  fpFreeList.walk.bits := PopCount(io.roqCommits.valid.zip(io.roqCommits.info).map{case (v, i) => v && needDestRegCommit(true, i)})
  intFreeList.walk.bits := PopCount(io.roqCommits.valid.zip(io.roqCommits.info).map{case (v, i) => v && needDestRegCommit(false, i)})
93
  // walk has higher priority than allocation and thus we don't use isWalk here
94 95
  fpFreeList.req.doAlloc := intFreeList.req.canAlloc && io.out(0).ready
  intFreeList.req.doAlloc := fpFreeList.req.canAlloc && io.out(0).ready
96

97 98 99
  // speculatively assign the instruction with an roqIdx
  val validCount = PopCount(io.in.map(_.valid))
  val roqIdxHead = RegInit(0.U.asTypeOf(new RoqPtr))
100 101 102 103 104 105 106 107 108
  val lastCycleMisprediction = RegNext(io.redirect.valid && !io.redirect.bits.flushItself())
  val roqIdxHeadNext = Mux(io.flush,
    0.U.asTypeOf(new RoqPtr),
    Mux(io.redirect.valid,
      io.redirect.bits.roqIdx,
      Mux(lastCycleMisprediction,
        roqIdxHead + 1.U,
        Mux(canOut, roqIdxHead + validCount, roqIdxHead))
    )
109 110 111
  )
  roqIdxHead := roqIdxHeadNext

Y
Yinan Xu 已提交
112 113 114
  /**
    * Rename: allocate free physical register and update rename table
    */
115 116 117
  val uops = Wire(Vec(RenameWidth, new MicroOp))

  uops.foreach( uop => {
Y
Yinan Xu 已提交
118 119
//    uop.brMask := DontCare
//    uop.brTag := DontCare
120 121 122
    uop.srcState(0) := DontCare
    uop.srcState(1) := DontCare
    uop.srcState(2) := DontCare
123
    uop.roqIdx := DontCare
124
    uop.diffTestDebugLrScValid := DontCare
Y
Yinan Xu 已提交
125
    uop.debugInfo := DontCare
126 127
    uop.lqIdx := DontCare
    uop.sqIdx := DontCare
128 129
  })

130 131
  val needFpDest = Wire(Vec(RenameWidth, Bool()))
  val needIntDest = Wire(Vec(RenameWidth, Bool()))
132
  val hasValid = Cat(io.in.map(_.valid)).orR
Y
Yinan Xu 已提交
133
  for (i <- 0 until RenameWidth) {
134 135 136
    uops(i).cf := io.in(i).bits.cf
    uops(i).ctrl := io.in(i).bits.ctrl

137
    val inValid = io.in(i).valid
L
LinJiawei 已提交
138

139
    // alloc a new phy reg
140 141
    needFpDest(i) := inValid && needDestReg(fp = true, io.in(i).bits)
    needIntDest(i) := inValid && needDestReg(fp = false, io.in(i).bits)
142 143
    fpFreeList.req.allocReqs(i) := needFpDest(i)
    intFreeList.req.allocReqs(i) := needIntDest(i)
L
LinJiawei 已提交
144

145
    io.in(i).ready := !hasValid || canOut
L
LinJiawei 已提交
146 147

    // do checkpoints when a branch inst come
Y
Yinan Xu 已提交
148 149 150 151
    // for(fl <- Seq(fpFreeList, intFreeList)){
    //   fl.cpReqs(i).valid := inValid
    //   fl.cpReqs(i).bits := io.in(i).bits.brTag
    // }
L
LinJiawei 已提交
152

153
    uops(i).pdest := Mux(needIntDest(i),
154
      intFreeList.req.pdests(i),
L
LinJiawei 已提交
155 156
      Mux(
        uops(i).ctrl.ldest===0.U && uops(i).ctrl.rfWen,
157
        0.U, fpFreeList.req.pdests(i)
L
LinJiawei 已提交
158 159
      )
    )
160

161 162
    uops(i).roqIdx := roqIdxHead + i.U

163
    io.out(i).valid := io.in(i).valid && intFreeList.req.canAlloc && fpFreeList.req.canAlloc && !io.roqCommits.isWalk
164 165
    io.out(i).bits := uops(i)

Y
Yinan Xu 已提交
166 167 168
    // write speculative rename table
    allPhyResource.map{ case (rat, freelist, _) =>
      val specWen = freelist.req.allocReqs(i) && freelist.req.canAlloc && freelist.req.doAlloc && !io.roqCommits.isWalk
L
LinJiawei 已提交
169

Y
Yinan Xu 已提交
170 171 172
      rat.specWritePorts(i).wen := specWen
      rat.specWritePorts(i).addr := uops(i).ctrl.ldest
      rat.specWritePorts(i).wdata := freelist.req.pdests(i)
173

Y
Yinan Xu 已提交
174
      freelist.deallocReqs(i) := specWen
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
    }

    // read rename table
    def readRat(lsrcList: List[UInt], ldest: UInt, fp: Boolean) = {
      val rat = if(fp) fpRat else intRat
      val srcCnt = lsrcList.size
      val psrcVec = Wire(Vec(srcCnt, UInt(PhyRegIdxWidth.W)))
      val old_pdest = Wire(UInt(PhyRegIdxWidth.W))
      for(k <- 0 until srcCnt+1){
        val rportIdx = i * (srcCnt+1) + k
        if(k != srcCnt){
          rat.readPorts(rportIdx).addr := lsrcList(k)
          psrcVec(k) := rat.readPorts(rportIdx).rdata
        } else {
          rat.readPorts(rportIdx).addr := ldest
          old_pdest := rat.readPorts(rportIdx).rdata
        }
      }
      (psrcVec, old_pdest)
    }
195
    val lsrcList = List(uops(i).ctrl.lsrc(0), uops(i).ctrl.lsrc(1), uops(i).ctrl.lsrc(2))
196 197 198
    val ldest = uops(i).ctrl.ldest
    val (intPhySrcVec, intOldPdest) = readRat(lsrcList.take(2), ldest, fp = false)
    val (fpPhySrcVec, fpOldPdest) = readRat(lsrcList, ldest, fp = true)
199 200 201
    uops(i).psrc(0) := Mux(uops(i).ctrl.srcType(0) === SrcType.reg, intPhySrcVec(0), fpPhySrcVec(0))
    uops(i).psrc(1) := Mux(uops(i).ctrl.srcType(1) === SrcType.reg, intPhySrcVec(1), fpPhySrcVec(1))
    uops(i).psrc(2) := fpPhySrcVec(2)
202 203 204
    uops(i).old_pdest := Mux(uops(i).ctrl.rfWen, intOldPdest, fpOldPdest)
  }

205 206 207 208
  // We don't bypass the old_pdest from valid instructions with the same ldest currently in rename stage.
  // Instead, we determine whether there're some dependences between the valid instructions.
  for (i <- 1 until RenameWidth) {
    io.renameBypass.lsrc1_bypass(i-1) := Cat((0 until i).map(j => {
209 210 211
      val fpMatch  = needFpDest(j) && io.in(i).bits.ctrl.srcType(0) === SrcType.fp
      val intMatch = needIntDest(j) && io.in(i).bits.ctrl.srcType(0) === SrcType.reg
      (fpMatch || intMatch) && io.in(j).bits.ctrl.ldest === io.in(i).bits.ctrl.lsrc(0)
212 213
    }).reverse)
    io.renameBypass.lsrc2_bypass(i-1) := Cat((0 until i).map(j => {
214 215 216
      val fpMatch  = needFpDest(j) && io.in(i).bits.ctrl.srcType(1) === SrcType.fp
      val intMatch = needIntDest(j) && io.in(i).bits.ctrl.srcType(1) === SrcType.reg
      (fpMatch || intMatch) && io.in(j).bits.ctrl.ldest === io.in(i).bits.ctrl.lsrc(1)
217 218
    }).reverse)
    io.renameBypass.lsrc3_bypass(i-1) := Cat((0 until i).map(j => {
219 220 221
      val fpMatch  = needFpDest(j) && io.in(i).bits.ctrl.srcType(2) === SrcType.fp
      val intMatch = needIntDest(j) && io.in(i).bits.ctrl.srcType(2) === SrcType.reg
      (fpMatch || intMatch) && io.in(j).bits.ctrl.ldest === io.in(i).bits.ctrl.lsrc(2)
222 223 224 225 226 227
    }).reverse)
    io.renameBypass.ldest_bypass(i-1) := Cat((0 until i).map(j => {
      val fpMatch  = needFpDest(j) && needFpDest(i)
      val intMatch = needIntDest(j) && needIntDest(i)
      (fpMatch || intMatch) && io.in(j).bits.ctrl.ldest === io.in(i).bits.ctrl.ldest
    }).reverse)
228 229 230 231
    io.renameBypass.move_eliminated_src1(i-1) :=
      // the producer move instruction writes to non-zero register
      io.in(i-1).bits.ctrl.isMove && io.in(i-1).bits.ctrl.ldest =/= 0.U &&
      // the consumer instruction uses the move's destination register
232
      io.in(i).bits.ctrl.srcType(0) === SrcType.reg && io.in(i).bits.ctrl.lsrc(0) === io.in(i-1).bits.ctrl.ldest &&
233 234 235 236 237 238
      // CSR control (by srnctl)
      io.csrCtrl.move_elim_enable
    io.renameBypass.move_eliminated_src2(i-1) :=
      // the producer move instruction writes to non-zero register
      io.in(i-1).bits.ctrl.isMove && io.in(i-1).bits.ctrl.ldest =/= 0.U &&
      // the consumer instruction uses the move's destination register
239
      io.in(i).bits.ctrl.srcType(1) === SrcType.reg && io.in(i).bits.ctrl.lsrc(1) === io.in(i-1).bits.ctrl.ldest &&
240 241
      // CSR control (by srnctl)
      io.csrCtrl.move_elim_enable
242
  }
Y
Yinan Xu 已提交
243

244 245 246 247 248 249
  val isLs    = VecInit(uops.map(uop => FuType.isLoadStore(uop.ctrl.fuType)))
  val isStore = VecInit(uops.map(uop => FuType.isStoreExu(uop.ctrl.fuType)))
  val isAMO   = VecInit(uops.map(uop => FuType.isAMO(uop.ctrl.fuType)))
  io.dispatchInfo.lsqNeedAlloc := VecInit((0 until RenameWidth).map(i =>
    Mux(isLs(i), Mux(isStore(i) && !isAMO(i), 2.U, 1.U), 0.U)))

Y
Yinan Xu 已提交
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
  /**
    * Instructions commit: update freelist and rename table
    */
  for (i <- 0 until CommitWidth) {
    if (i >= RenameWidth) {
      allPhyResource.map{ case (rat, _, _) =>
        rat.specWritePorts(i).wen   := false.B
        rat.specWritePorts(i).addr  := DontCare
        rat.specWritePorts(i).wdata := DontCare
      }
    }

    allPhyResource.map{ case (rat, freelist, fp) =>
      // walk back write
      val commitDestValid = io.roqCommits.valid(i) && needDestRegCommit(fp, io.roqCommits.info(i))

      when (commitDestValid && io.roqCommits.isWalk) {
        rat.specWritePorts(i).wen := true.B
        rat.specWritePorts(i).addr := io.roqCommits.info(i).ldest
        rat.specWritePorts(i).wdata := io.roqCommits.info(i).old_pdest
        XSInfo({if(fp) p"fp" else p"int "} + p"walk: " +
          p" ldest:${rat.specWritePorts(i).addr} old_pdest:${rat.specWritePorts(i).wdata}\n")
      }

      rat.archWritePorts(i).wen := commitDestValid && !io.roqCommits.isWalk
      rat.archWritePorts(i).addr := io.roqCommits.info(i).ldest
      rat.archWritePorts(i).wdata := io.roqCommits.info(i).pdest

      XSInfo(rat.archWritePorts(i).wen,
        {if(fp) p"fp" else p"int "} + p" rat arch: ldest:${rat.archWritePorts(i).addr}" +
          p" pdest:${rat.archWritePorts(i).wdata}\n"
      )

      freelist.deallocReqs(i) := rat.archWritePorts(i).wen
      freelist.deallocPregs(i) := io.roqCommits.info(i).old_pdest
    }
  }
Y
Yinan Xu 已提交
287

288 289 290 291 292 293 294
  XSPerfAccumulate("in", Mux(RegNext(io.in(0).ready), PopCount(io.in.map(_.valid)), 0.U))
  XSPerfAccumulate("utilization", PopCount(io.in.map(_.valid)))
  XSPerfAccumulate("waitInstr", PopCount((0 until RenameWidth).map(i => io.in(i).valid && !io.in(i).ready)))
  XSPerfAccumulate("stall_cycle_dispatch", hasValid && !io.out(0).ready && fpFreeList.req.canAlloc && intFreeList.req.canAlloc && !io.roqCommits.isWalk)
  XSPerfAccumulate("stall_cycle_fp", hasValid && io.out(0).ready && !fpFreeList.req.canAlloc && intFreeList.req.canAlloc && !io.roqCommits.isWalk)
  XSPerfAccumulate("stall_cycle_int", hasValid && io.out(0).ready && fpFreeList.req.canAlloc && !intFreeList.req.canAlloc && !io.roqCommits.isWalk)
  XSPerfAccumulate("stall_cycle_walk", hasValid && io.out(0).ready && fpFreeList.req.canAlloc && intFreeList.req.canAlloc && io.roqCommits.isWalk)
Y
Yinan Xu 已提交
295

296

297
}