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
  }
L
Lingrui98 已提交
170
  val u = io.update.bits
Y
Yinan Xu 已提交
171

L
Lingrui98 已提交
172 173
  val cfi_pc = packetAligned(u.ftqPC) + (u.cfiIndex.bits << instOffsetBits)
  val new_target = u.target
174
  val new_lower = new_target(lowerBitsSize+instOffsetBits-1, instOffsetBits)
L
Lingrui98 已提交
175
  val update_pc_higher     = cfi_pc(VAddrBits-1, lowerBitsSize+instOffsetBits)
176 177 178
  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 已提交
179 180


L
Lingrui98 已提交
181 182 183 184 185 186 187
  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)
188
  val dataWrite = BtbDataEntry(new_lower, new_extended)
L
Lingrui98 已提交
189
  
Y
Yinan Xu 已提交
190

L
Lingrui98 已提交
191
  val updateValid = io.update.valid && updateTaken
Y
Yinan Xu 已提交
192
  // Update btb
L
Lingrui98 已提交
193 194 195 196 197 198
  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 已提交
199 200 201 202

  if (BPUDebug && debug) {
    val debug_verbose = true
    val validLatch = RegNext(io.pc.valid)
203
    XSDebug(io.pc.valid, "read: pc=0x%x, mask=%b\n", if1_packetAlignedPC, if1_mask)
Y
Yinan Xu 已提交
204 205 206 207 208
    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 已提交
209 210
          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 已提交
211 212 213 214 215
        }
      }
    }

    for (i <- 0 until BtbBanks) {
L
Lingrui98 已提交
216 217
      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 已提交
218
    }
219
    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 已提交
220
      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 已提交
221 222 223 224 225 226 227 228 229 230
    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
  }

  }
231
}