Btb.scala 8.8 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 78 79

  val data = List.fill(BtbWays) {
    List.fill(BtbBanks) {
80
      Module(new SRAMTemplate(new BtbDataEntry, set = nRows, shouldReset = true, holdRead = true))
Y
Yinan Xu 已提交
81 82 83 84
    }
  }
  val meta = List.fill(BtbWays) {
    List.fill(BtbBanks) {
85
      Module(new SRAMTemplate(new BtbMetaEntry, set = nRows, shouldReset = true, holdRead = true))
Y
Yinan Xu 已提交
86 87
    }
  }
88
  val edata = Module(new SRAMTemplate(UInt(VAddrBits.W), set = extendedNRows, shouldReset = true, holdRead = true))
Y
Yinan Xu 已提交
89

90 91 92 93 94
  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 已提交
95 96 97
  // BTB read requests
  for (w <- 0 until BtbWays) {
    for (b <- 0 until BtbBanks) {
98
      meta(w)(b).io.r.req.valid       := if1_mask(b) && io.pc.valid
L
Lingrui98 已提交
99
      meta(w)(b).io.r.req.bits.setIdx := if1_row
100
      data(w)(b).io.r.req.valid       := if1_mask(b) && io.pc.valid
L
Lingrui98 已提交
101
      data(w)(b).io.r.req.bits.setIdx := if1_row
Y
Yinan Xu 已提交
102 103
    }
  }
104 105
  edata.io.r.req.valid       := io.pc.valid
  edata.io.r.req.bits.setIdx := if1_row
Y
Yinan Xu 已提交
106 107 108 109

  // Entries read from SRAM
  val if2_metaRead = VecInit((0 until BtbWays).map(w => VecInit((0 until BtbBanks).map( b => meta(w)(b).io.r.resp.data(0)))))
  val if2_dataRead = VecInit((0 until BtbWays).map(w => VecInit((0 until BtbBanks).map( b => data(w)(b).io.r.resp.data(0)))))
110
  val if2_edataRead = edata.io.r.resp.data(0)
Y
Yinan Xu 已提交
111

112
  val if2_tag = btbAddr.getTag(if2_pc)
Y
Yinan Xu 已提交
113 114 115 116

  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!
117
      if2_metaRead(w)(b).tag === if2_tag && if2_metaRead(w)(b).valid && if2_mask(b)
Y
Yinan Xu 已提交
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
    ))
  ))
  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,
145
             if2_tag)))
Y
Yinan Xu 已提交
146 147 148 149 150 151 152 153

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



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

  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 已提交
173
  val u = io.update.bits
Y
Yinan Xu 已提交
174

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


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

L
Lingrui98 已提交
194 195
  // val jalFirstEncountered = !u.isMisPred && !u.bpuMeta.btbHitJal && updateType === BTBtype.J
  val updateValid = io.update.valid && updateTaken
Y
Yinan Xu 已提交
196 197 198
  // Update btb
  for (w <- 0 until BtbWays) {
    for (b <- 0 until BtbBanks) {
L
Lingrui98 已提交
199
      meta(w)(b).io.w.req.valid := updateValid && b.U === updateBank && w.U === updateWay
Y
Yinan Xu 已提交
200
      meta(w)(b).io.w.req.bits.setIdx := updateRow
201
      meta(w)(b).io.w.req.bits.data := VecInit(metaWrite)
L
Lingrui98 已提交
202
      data(w)(b).io.w.req.valid := updateValid && b.U === updateBank && w.U === updateWay
Y
Yinan Xu 已提交
203
      data(w)(b).io.w.req.bits.setIdx := updateRow
204
      data(w)(b).io.w.req.bits.data := VecInit(dataWrite)
Y
Yinan Xu 已提交
205 206 207
    }
  }

208 209
  edata.io.w.req.valid := updateValid && new_extended
  edata.io.w.req.bits.setIdx := updateRow
210
  edata.io.w.req.bits.data := VecInit(u.target)
Y
Yinan Xu 已提交
211 212 213 214 215


  if (BPUDebug && debug) {
    val debug_verbose = true
    val validLatch = RegNext(io.pc.valid)
216
    XSDebug(io.pc.valid, "read: pc=0x%x, mask=%b\n", if1_packetAlignedPC, if1_mask)
Y
Yinan Xu 已提交
217 218 219 220 221
    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 已提交
222 223
          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 已提交
224 225 226 227 228
        }
      }
    }

    for (i <- 0 until BtbBanks) {
L
Lingrui98 已提交
229 230
      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 已提交
231
    }
232
    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 已提交
233
      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 已提交
234 235 236 237 238 239 240 241 242 243
    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
  }

  }
244
}