Btb.scala 8.4 KB
Newer Older
Y
Yinan Xu 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
package xiangshan.frontend

import chisel3._
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
import chisel3.util._
import xiangshan._
import xiangshan.backend.ALUOpType
import utils._
import chisel3.experimental.chiselName


import scala.math.min

14
trait BTBParams extends HasXSParameter with HasIFUConst {
Y
Yinan Xu 已提交
15 16
  val nRows = BtbSize / (PredictWidth * BtbWays)
  val offsetLen = 13
17
  val lowerBitsSize = 13
Y
Yinan Xu 已提交
18 19 20 21
  val extendedNRows = nRows
}

class BtbDataEntry extends XSBundle with BTBParams {
22
  val lower = UInt(lowerBitsSize.W)
Y
Yinan Xu 已提交
23 24 25 26
  val extended = Bool()
}

object BtbDataEntry {
27
  def apply(lower: UInt, extended: Bool) = {
Y
Yinan Xu 已提交
28
    val e = Wire(new BtbDataEntry)
29
    e.lower := lower
Y
Yinan Xu 已提交
30 31 32 33 34 35 36 37
    e.extended := extended
    e
  }
}

class BtbMetaEntry() extends XSBundle with BTBParams {
  val valid = Bool()
  // TODO: don't need full length of tag
38
  val tag = UInt((VAddrBits - log2Ceil(nRows) - log2Ceil(PredictWidth) - instOffsetBits).W)
L
Lingrui98 已提交
39
  val isBr = Bool()
Y
Yinan Xu 已提交
40 41 42 43
  val isRVC = Bool()
}

object BtbMetaEntry {
L
Lingrui98 已提交
44
  def apply(tag: UInt, isBr: UInt, isRVC: Bool) = {
Y
Yinan Xu 已提交
45 46 47
    val e = Wire(new BtbMetaEntry)
    e.valid := true.B
    e.tag := tag
L
Lingrui98 已提交
48
    e.isBr := isBr
Y
Yinan Xu 已提交
49 50 51 52 53 54 55 56 57
    e.isRVC := isRVC
    e
  }
}

class BTB extends BasePredictor with BTBParams{
  class BTBResp extends Resp {
    val targets = Vec(PredictWidth, UInt(VAddrBits.W))
    val hits = Vec(PredictWidth, Bool())
L
Lingrui98 已提交
58
    val isBrs = Vec(PredictWidth, Bool())
Y
Yinan Xu 已提交
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
    val isRVC = Vec(PredictWidth, Bool())
  }
  class BTBMeta extends Meta {
    val writeWay =  Vec(PredictWidth, UInt(log2Up(BtbWays).W))
  }
  class BTBFromOthers extends FromOthers {}

  class BTBIO extends DefaultBasePredictorIO {
    val resp = Output(new BTBResp)
    val meta = Output(new BTBMeta)
  }
  override val debug = true
  override val io = IO(new BTBIO)
  val btbAddr = new TableAddr(log2Up(BtbSize/BtbWays), BtbBanks)

74
  val if1_packetAlignedPC = packetAligned(io.pc.bits)
Y
Yinan Xu 已提交
75

76
  val if2_pc = RegEnable(if1_packetAlignedPC, io.pc.valid)
Y
Yinan Xu 已提交
77

L
Lingrui98 已提交
78 79 80 81
  // layout: way 0 bank 0, way 0 bank 1, ..., way 0 bank BtbBanks-1, way 1 bank 0, ..., way 1 bank BtbBanks-1
  val data = Module(new SRAMTemplate(new BtbDataEntry, set = nRows, way=BtbWays*BtbBanks, shouldReset = true, holdRead = true))
  val meta = Module(new SRAMTemplate(new BtbMetaEntry, set = nRows, way=BtbWays*BtbBanks, shouldReset = true, holdRead = true))

82
  val edata = Module(new SRAMTemplate(UInt(VAddrBits.W), set = extendedNRows, shouldReset = true, holdRead = true))
Y
Yinan Xu 已提交
83

84 85 86 87 88
  val if1_mask = io.inMask
  val if2_mask = RegEnable(if1_mask, io.pc.valid)
  val if1_row = btbAddr.getBankIdx(if1_packetAlignedPC)
  val if2_row = RegEnable(if1_row, io.pc.valid)
  
Y
Yinan Xu 已提交
89
  // BTB read requests
L
Lingrui98 已提交
90 91 92 93 94
  meta.io.r.req.valid  := io.pc.valid
  data.io.r.req.valid  := io.pc.valid
  edata.io.r.req.valid := io.pc.valid
  meta.io.r.req.bits.setIdx  := if1_row
  data.io.r.req.bits.setIdx  := if1_row
95
  edata.io.r.req.bits.setIdx := if1_row
L
Lingrui98 已提交
96
  
Y
Yinan Xu 已提交
97 98

  // Entries read from SRAM
L
Lingrui98 已提交
99 100 101 102 103 104 105 106
  val if2_metaRead =
    VecInit((0 until BtbWays).map(
      w => VecInit((0 until BtbBanks).map(
        b => meta.io.r.resp.data(w*BtbBanks+b)))))
  val if2_dataRead =
    VecInit((0 until BtbWays).map(
      w => VecInit((0 until BtbBanks).map(
        b => data.io.r.resp.data(w*BtbBanks+b)))))
107
  val if2_edataRead = edata.io.r.resp.data(0)
Y
Yinan Xu 已提交
108

109
  val if2_tag = btbAddr.getTag(if2_pc)
Y
Yinan Xu 已提交
110 111 112 113

  val if2_totalHits = VecInit((0 until BtbBanks).map( b =>
    VecInit((0 until BtbWays).map( w =>
      // This should correspond to the real mask from last valid cycle!
114
      if2_metaRead(w)(b).tag === if2_tag && if2_metaRead(w)(b).valid && if2_mask(b)
Y
Yinan Xu 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
    ))
  ))
  val if2_bankHits = VecInit(if2_totalHits.map(_.reduce(_||_)))
  val if2_bankHitWays = VecInit(if2_totalHits.map(PriorityEncoder(_)))


  def allocWay(valids: UInt, meta_tags: UInt, req_tag: UInt) = {
    val randomAlloc = true
    if (BtbWays > 1) {
      val w = Wire(UInt(log2Up(BtbWays).W))
      val valid = WireInit(valids.andR)
      val tags = Cat(meta_tags, req_tag)
      val l = log2Up(BtbWays)
      val nChunks = (tags.getWidth + l - 1) / l
      val chunks = (0 until nChunks).map( i =>
        tags(min((i+1)*l, tags.getWidth)-1, i*l)
      )
      w := Mux(valid, if (randomAlloc) {LFSR64()(log2Up(BtbWays)-1,0)} else {chunks.reduce(_^_)}, PriorityEncoder(~valids))
      w
    } else {
      val w = WireInit(0.U)
      w
    }
  }
  val allocWays = VecInit((0 until BtbBanks).map(b =>
    allocWay(VecInit(if2_metaRead.map(w => w(b).valid)).asUInt,
             VecInit(if2_metaRead.map(w => w(b).tag)).asUInt,
142
             if2_tag)))
Y
Yinan Xu 已提交
143 144 145 146 147 148 149 150

  val writeWay = VecInit((0 until BtbBanks).map(
    b => Mux(if2_bankHits(b), if2_bankHitWays(b), allocWays(b))
  ))



  for (b <- 0 until BtbBanks) {
151 152
    val meta_entry = if2_metaRead(if2_bankHitWays(b))(b)
    val data_entry = if2_dataRead(if2_bankHitWays(b))(b)
Y
Yinan Xu 已提交
153
    // Use real pc to calculate the target
154
    io.resp.targets(b) := Mux(data_entry.extended, if2_edataRead, Cat(if2_pc(VAddrBits-1, lowerBitsSize+instOffsetBits), data_entry.lower, 0.U(instOffsetBits.W)))
155
    io.resp.hits(b)  := if2_bankHits(b)
L
Lingrui98 已提交
156
    io.resp.isBrs(b) := meta_entry.isBr
Y
Yinan Xu 已提交
157
    io.resp.isRVC(b) := meta_entry.isRVC
158
    io.meta.writeWay(b) := writeWay(b)
L
Lingrui98 已提交
159
    // io.meta.hitJal(b)   := if2_bankHits(b) && meta_entry.btbType === BTBtype.J
Y
Yinan Xu 已提交
160 161 162 163 164 165 166 167 168 169
  }

  def pdInfoToBTBtype(pd: PreDecodeInfo) = {
    val t = WireInit(0.U(2.W))
    when (pd.isJalr) { t := BTBtype.I}
    when (pd.isRet)  { t := BTBtype.R}
    when (pd.isJal)  { t := BTBtype.J}
    when (pd.isBr)   { t := BTBtype.B}
    t
  }
170 171 172
  
  val do_update = RegNext(io.update)
  val u = do_update.bits
Y
Yinan Xu 已提交
173

L
Lingrui98 已提交
174 175
  val cfi_pc = packetAligned(u.ftqPC) + (u.cfiIndex.bits << instOffsetBits)
  val new_target = u.target
176
  val new_lower = new_target(lowerBitsSize+instOffsetBits-1, instOffsetBits)
L
Lingrui98 已提交
177
  val update_pc_higher     = cfi_pc(VAddrBits-1, lowerBitsSize+instOffsetBits)
178 179 180
  val update_target_higher = new_target(VAddrBits-1, lowerBitsSize+instOffsetBits)
  val higher_identical = update_pc_higher === update_target_higher
  val new_extended = !higher_identical
Y
Yinan Xu 已提交
181 182


L
Lingrui98 已提交
183 184 185 186 187 188 189
  val updateWay = u.metas(u.cfiIndex.bits).btbWriteWay
  val updateBank = u.cfiIndex.bits
  val updateRow = btbAddr.getBankIdx(cfi_pc)
  val updateIsBr = u.br_mask(u.cfiIndex.bits)
  val updateTaken = u.cfiIndex.valid
  // TODO: remove isRVC
  val metaWrite = BtbMetaEntry(btbAddr.getTag(cfi_pc), updateIsBr, u.cfiIsRVC)
190
  val dataWrite = BtbDataEntry(new_lower, new_extended)
L
Lingrui98 已提交
191
  
Y
Yinan Xu 已提交
192

193
  val updateValid = do_update.valid && updateTaken
Y
Yinan Xu 已提交
194
  // Update btb
L
Lingrui98 已提交
195 196 197 198 199 200
  require(isPow2(BtbBanks))
  // this is one hot, since each fetch bundle has at most 1 taken instruction
  val updateWayMask = UIntToOH(Cat(updateWay, updateBank))
  meta.io.w.apply(updateValid, metaWrite, updateRow, updateWayMask)
  data.io.w.apply(updateValid, dataWrite, updateRow, updateWayMask)
  edata.io.w.apply(updateValid && new_extended, u.target, updateRow, "b1".U)
Y
Yinan Xu 已提交
201 202 203 204

  if (BPUDebug && debug) {
    val debug_verbose = true
    val validLatch = RegNext(io.pc.valid)
205
    XSDebug(io.pc.valid, "read: pc=0x%x, mask=%b\n", if1_packetAlignedPC, if1_mask)
Y
Yinan Xu 已提交
206 207 208 209 210
    XSDebug(validLatch, "read_resp: pc=0x%x, readIdx=%d-------------------------------\n",
      if2_pc, btbAddr.getIdx(if2_pc))
    if (debug_verbose) {
      for (i <- 0 until BtbBanks){
        for (j <- 0 until BtbWays) {
L
Lingrui98 已提交
211 212
          XSDebug(validLatch, "read_resp[w=%d][b=%d][r=%d] is valid(%d) mask(%d), tag=0x%x, lower=0x%x, isBr=%d, isExtend=%d, isRVC=%d\n",
          j.U, i.U, if2_row, if2_metaRead(j)(i).valid, if2_mask(i), if2_metaRead(j)(i).tag, if2_dataRead(j)(i).lower, if2_metaRead(j)(i).isBr, if2_dataRead(j)(i).extended, if2_metaRead(j)(i).isRVC)
Y
Yinan Xu 已提交
213 214 215 216 217
        }
      }
    }

    for (i <- 0 until BtbBanks) {
L
Lingrui98 已提交
218 219
      XSDebug(validLatch && if2_bankHits(i), "resp(%d): bank(%d) hits, tgt=%x, isRVC=%d, isBr=%d\n",
        i.U, i.U, io.resp.targets(i), io.resp.isRVC(i), io.resp.isBrs(i))
Y
Yinan Xu 已提交
220
    }
221
    XSDebug(updateValid, "update_req: cycle=%d, pc=0x%x, target=0x%x, misPred=%d, lower=%x, extended=%d, way=%d, bank=%d, row=0x%x\n",
L
Lingrui98 已提交
222
      u.metas(u.cfiIndex.bits).debug_btb_cycle, cfi_pc, new_target, u.mispred(u.cfiIndex.bits), new_lower, new_extended, updateWay, updateBank, updateRow)
Y
Yinan Xu 已提交
223 224 225 226 227 228 229 230 231 232
    for (i <- 0 until BtbBanks) {
      // Conflict when not hit and allocating a valid entry
      val conflict = if2_metaRead(allocWays(i))(i).valid && !if2_bankHits(i)
      XSDebug(conflict, "bank(%d) is trying to allocate a valid way(%d)\n", i.U, allocWays(i))
      // There is another circumstance when a branch is on its way to update while another
      // branch chose the same way to udpate, then after the first branch is wrote in,
      // the second branch will overwrite the first branch
  }

  }
233
}