Btb.scala 11.0 KB
Newer Older
L
Lingrui98 已提交
1 2 3
package xiangshan.frontend

import chisel3._
4
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
L
Lingrui98 已提交
5 6 7 8 9
import chisel3.util._
import xiangshan._
import xiangshan.backend.ALUOpType
import utils._
import xiangshan.backend.decode.XSTrap
L
Lingrui98 已提交
10 11
import chisel3.experimental.chiselName

L
Lingrui98 已提交
12

L
Lingrui98 已提交
13 14
import scala.math.min

L
Lingrui98 已提交
15 16
trait BTBParams extends HasXSParameter {
  val nRows = BtbSize / (PredictWidth * BtbWays)
L
Lingrui98 已提交
17
  val offsetLen = 13
L
Lingrui98 已提交
18
  val extendedNRows = nRows
L
Lingrui98 已提交
19 20
}

21
class BtbDataEntry extends XSBundle with BTBParams {
L
Lingrui98 已提交
22
  val offset = SInt(offsetLen.W)
L
Lingrui98 已提交
23
  val extended = Bool()
L
Lingrui98 已提交
24 25
}

26 27 28 29 30 31 32 33 34 35
object BtbDataEntry {
  def apply(offset: SInt, extended: Bool) = {
    val e = Wire(new BtbDataEntry)
    e.offset := offset
    e.extended := extended
    e
  }
}

class BtbMetaEntry() extends XSBundle with BTBParams {
L
Lingrui98 已提交
36 37 38 39 40
  val valid = Bool()
  // TODO: don't need full length of tag
  val tag = UInt((VAddrBits - log2Up(BtbSize) - 1).W)
  val btbType = UInt(2.W)
  val isRVC = Bool()
41 42 43 44 45 46 47 48 49 50 51
}

object BtbMetaEntry {
  def apply(tag: UInt, btbType: UInt, isRVC: Bool) = {
    val e = Wire(new BtbMetaEntry)
    e.valid := true.B
    e.tag := tag
    e.btbType := btbType
    e.isRVC := isRVC
    e
  }
L
Lingrui98 已提交
52 53
}

L
Lingrui98 已提交
54 55
class BTB extends BasePredictor with BTBParams{
  class BTBResp extends Resp {
L
Lingrui98 已提交
56 57
    val targets = Vec(PredictWidth, UInt(VAddrBits.W))
    val hits = Vec(PredictWidth, Bool())
L
Lingrui98 已提交
58 59 60 61
    val types = Vec(PredictWidth, UInt(2.W))
    val isRVC = Vec(PredictWidth, Bool())
  }
  class BTBMeta extends Meta {
L
Lingrui98 已提交
62
    val writeWay =  Vec(PredictWidth, UInt(log2Up(BtbWays).W))
G
GouLingrui 已提交
63
    val hitJal = Vec(PredictWidth, Bool())
L
Lingrui98 已提交
64
  }
L
Lingrui98 已提交
65 66
  class BTBFromOthers extends FromOthers {}
  
L
Lingrui98 已提交
67 68 69 70
  class BTBIO extends DefaultBasePredictorIO {
    val resp = Output(new BTBResp)
    val meta = Output(new BTBMeta)
  }
71
  override val debug = true
L
Lingrui98 已提交
72
  override val io = IO(new BTBIO)
G
GouLingrui 已提交
73
  val btbAddr = new TableAddr(log2Up(BtbSize/BtbWays), BtbBanks)
L
Lingrui98 已提交
74

75
  val if1_bankAlignedPC = bankAligned(io.pc.bits)
L
Lingrui98 已提交
76

77
  val if2_pc = RegEnable(if1_bankAlignedPC, io.pc.valid)
L
Lingrui98 已提交
78

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

  // BTB read requests
L
Lingrui98 已提交
92

L
Lingrui98 已提交
93
  // this bank means cache bank
94
  val if1_startsAtOddBank = bankInGroup(if1_bankAlignedPC)(0)
L
Lingrui98 已提交
95

96
  val if1_baseBank = btbAddr.getBank(if1_bankAlignedPC)
L
Lingrui98 已提交
97

98
  val if1_realMask = Mux(if1_startsAtOddBank,
L
Lingrui98 已提交
99 100
                      Cat(io.inMask(bankWidth-1,0), io.inMask(PredictWidth-1, bankWidth)),
                      io.inMask)
G
GouLingrui 已提交
101

102
  val if2_realMask = RegEnable(if1_realMask, io.pc.valid)
L
Lingrui98 已提交
103

104
  val if1_isInNextRow = VecInit((0 until BtbBanks).map(i => Mux(if1_startsAtOddBank, (i < bankWidth).B, false.B)))
L
Lingrui98 已提交
105

106
  val if1_baseRow = btbAddr.getBankIdx(if1_bankAlignedPC)
L
Lingrui98 已提交
107
  
108
  val if1_nextRowStartsUp = if1_baseRow.andR
L
Lingrui98 已提交
109

110
  val if1_realRow = VecInit((0 until BtbBanks).map(b => Mux(if1_isInNextRow(b), (if1_baseRow+1.U)(log2Up(nRows)-1, 0), if1_baseRow)))
L
Lingrui98 已提交
111

112
  val if2_realRow = VecInit(if1_realRow.map(RegEnable(_, enable=io.pc.valid)))
L
Lingrui98 已提交
113 114 115

  for (w <- 0 until BtbWays) {
    for (b <- 0 until BtbBanks) {
116 117 118 119
      meta(w)(b).io.r.req.valid       := if1_realMask(b) && io.pc.valid
      meta(w)(b).io.r.req.bits.setIdx := if1_realRow(b)
      data(w)(b).io.r.req.valid       := if1_realMask(b) && io.pc.valid
      data(w)(b).io.r.req.bits.setIdx := if1_realRow(b)
L
Lingrui98 已提交
120 121
    }
  }
L
Lingrui98 已提交
122 123
  for (b <- 0 to 1) {
    edata(b).io.r.req.valid       := io.pc.valid
124 125
    val row = if (b == 0) { Mux(if1_startsAtOddBank, if1_realRow(bankWidth), if1_realRow(0)) }
              else { Mux(if1_startsAtOddBank, if1_realRow(0), if1_realRow(bankWidth))}
L
Lingrui98 已提交
126 127
    edata(b).io.r.req.bits.setIdx := row
  }
L
Lingrui98 已提交
128 129

  // Entries read from SRAM
130 131 132
  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)))))
  val if2_edataRead = VecInit((0 to 1).map(i => edata(i).io.r.resp.data(0)))
L
Lingrui98 已提交
133

134 135 136
  val if2_baseBank = btbAddr.getBank(if2_pc)
  val if2_startsAtOddBank = bankInGroup(if2_pc)(0)
  val if2_baseTag = btbAddr.getTag(if2_pc)
L
Lingrui98 已提交
137

138 139
  val if2_tagIncremented = VecInit((0 until BtbBanks).map(b => RegEnable(if1_isInNextRow(b.U) && if1_nextRowStartsUp, io.pc.valid)))
  val if2_realTags = VecInit((0 until BtbBanks).map(b => Mux(if2_tagIncremented(b), if2_baseTag + 1.U, if2_baseTag)))
L
Lingrui98 已提交
140

141
  val if2_totalHits = VecInit((0 until BtbBanks).map( b => 
L
Lingrui98 已提交
142
    VecInit((0 until BtbWays).map( w =>
L
Lingrui98 已提交
143
      // This should correspond to the real mask from last valid cycle!
144
      if2_metaRead(w)(b).tag === if2_realTags(b) && if2_metaRead(w)(b).valid && if2_realMask(b)
L
Lingrui98 已提交
145 146
    ))
  ))
147 148
  val if2_bankHits = VecInit(if2_totalHits.map(_.reduce(_||_)))
  val if2_bankHitWays = VecInit(if2_totalHits.map(PriorityEncoder(_)))
L
Lingrui98 已提交
149

L
Lingrui98 已提交
150

151
  def allocWay(valids: UInt, meta_tags: UInt, req_tag: UInt) = {
G
GouLingrui 已提交
152
    val randomAlloc = true
L
Lingrui98 已提交
153
    if (BtbWays > 1) {
154 155
      val w = Wire(UInt(log2Up(BtbWays).W))
      val valid = WireInit(valids.andR)
L
Lingrui98 已提交
156 157 158 159 160 161
      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)
      )
162
      w := Mux(valid, if (randomAlloc) {LFSR64()(log2Up(BtbWays)-1,0)} else {chunks.reduce(_^_)}, PriorityEncoder(~valids))
163
      w
L
Lingrui98 已提交
164
    } else {
165 166
      val w = WireInit(0.U)
      w
L
Lingrui98 已提交
167 168
    }
  }
169
  val allocWays = VecInit((0 until BtbBanks).map(b => 
170 171 172
    allocWay(VecInit(if2_metaRead.map(w => w(b).valid)).asUInt,
             VecInit(if2_metaRead.map(w => w(b).tag)).asUInt,
             if2_realTags(b))))
173

L
Lingrui98 已提交
174
  val writeWay = VecInit((0 until BtbBanks).map(
175
    b => Mux(if2_bankHits(b), if2_bankHitWays(b), allocWays(b))
L
Lingrui98 已提交
176
  ))
L
Lingrui98 已提交
177 178 179 180



  for (b <- 0 until BtbBanks) {
181 182 183 184 185 186
    val realBank = (if (b < bankWidth) Mux(if2_startsAtOddBank, (b+bankWidth).U, b.U)
                    else Mux(if2_startsAtOddBank, (b-bankWidth).U, b.U))
    val meta_entry = if2_metaRead(if2_bankHitWays(realBank))(realBank)
    val data_entry = if2_dataRead(if2_bankHitWays(realBank))(realBank)
    val edataBank = (if (b < bankWidth) Mux(if2_startsAtOddBank, 1.U, 0.U)
                     else Mux(if2_startsAtOddBank, 0.U, 1.U))
L
Lingrui98 已提交
187
    // Use real pc to calculate the target
188 189
    io.resp.targets(b) := Mux(data_entry.extended, if2_edataRead(edataBank), (if2_pc.asSInt + (b << 1).S + data_entry.offset).asUInt)
    io.resp.hits(b)  := if2_bankHits(realBank)
L
Lingrui98 已提交
190 191
    io.resp.types(b) := meta_entry.btbType
    io.resp.isRVC(b) := meta_entry.isRVC
L
Lingrui98 已提交
192
    io.meta.writeWay(b) := writeWay(realBank)
193
    io.meta.hitJal(b)   := if2_bankHits(realBank) && meta_entry.btbType === BTBtype.J
L
Lingrui98 已提交
194 195
  }

L
Lingrui98 已提交
196
  def pdInfoToBTBtype(pd: PreDecodeInfo) = {
L
Lingrui98 已提交
197
    val t = WireInit(0.U(2.W))
L
Lingrui98 已提交
198 199 200 201 202
    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 已提交
203
  }
L
Lingrui98 已提交
204
  val u = io.update.bits.ui
L
Lingrui98 已提交
205
  
L
Lingrui98 已提交
206 207 208
  val max_offset = Cat(0.B, ~(0.U((offsetLen-1).W))).asSInt
  val min_offset = Cat(1.B,  (0.U((offsetLen-1).W))).asSInt
  val new_target = Mux(u.pd.isBr, u.brTarget, u.target)
G
GouLingrui 已提交
209
  val new_offset = (new_target.asSInt - u.pc.asSInt)
L
Lingrui98 已提交
210
  val new_extended = (new_offset > max_offset || new_offset < min_offset)
L
Lingrui98 已提交
211

L
Lingrui98 已提交
212

L
Lingrui98 已提交
213
  val updateWay = u.brInfo.btbWriteWay
L
Lingrui98 已提交
214
  val updateBankIdx = btbAddr.getBank(u.pc)
L
Lingrui98 已提交
215
  val updateEBank = updateBankIdx(log2Ceil(BtbBanks)-1) // highest bit of bank idx
L
Lingrui98 已提交
216
  val updateRow = btbAddr.getBankIdx(u.pc)
217 218
  val updateType = pdInfoToBTBtype(u.pd)
  val metaWrite = BtbMetaEntry(btbAddr.getTag(u.pc), updateType, u.pd.isRVC)
219
  val dataWrite = BtbDataEntry(new_offset, new_extended)
L
Lingrui98 已提交
220

G
GouLingrui 已提交
221
  val jalFirstEncountered = !u.isMisPred && !u.brInfo.btbHitJal && updateType === BTBtype.J
222
  val updateValid = io.update.valid && (u.isMisPred || jalFirstEncountered)
L
Lingrui98 已提交
223 224 225 226 227 228 229 230 231 232
  // Update btb
  for (w <- 0 until BtbWays) {
    for (b <- 0 until BtbBanks) {
      meta(w)(b).io.w.req.valid := updateValid && b.U === updateBankIdx && w.U === updateWay
      meta(w)(b).io.w.req.bits.setIdx := updateRow
      meta(w)(b).io.w.req.bits.data := metaWrite
      data(w)(b).io.w.req.valid := updateValid && b.U === updateBankIdx && w.U === updateWay
      data(w)(b).io.w.req.bits.setIdx := updateRow
      data(w)(b).io.w.req.bits.data := dataWrite
    }
L
Lingrui98 已提交
233
  }
L
Lingrui98 已提交
234 235 236 237 238 239
  
  for (b <- 0 to 1) {
    edata(b).io.w.req.valid := updateValid && new_extended && b.U === updateEBank
    edata(b).io.w.req.bits.setIdx := updateRow
    edata(b).io.w.req.bits.data := u.target
  }
L
Lingrui98 已提交
240

L
Lingrui98 已提交
241

242
  if (BPUDebug && debug) {
L
Lingrui98 已提交
243
    val debug_verbose = true
G
GouLingrui 已提交
244 245 246
    
    XSDebug("isInNextRow: ")
    (0 until BtbBanks).foreach(i => {
247
      XSDebug(false, true.B, "%d ", if1_isInNextRow(i))
G
GouLingrui 已提交
248 249
      if (i == BtbBanks-1) { XSDebug(false, true.B, "\n") }
    })
L
Lingrui98 已提交
250 251

    val validLatch = RegNext(io.pc.valid)
252
    XSDebug(io.pc.valid, "read: pc=0x%x, baseBank=%d, realMask=%b\n", if1_bankAlignedPC, if1_baseBank, if1_realMask)
L
Lingrui98 已提交
253
    XSDebug(validLatch, "read_resp: pc=0x%x, readIdx=%d-------------------------------\n",
254
      if2_pc, btbAddr.getIdx(if2_pc))
L
Lingrui98 已提交
255 256 257 258
    if (debug_verbose) {
      for (i <- 0 until BtbBanks){
        for (j <- 0 until BtbWays) {
          XSDebug(validLatch, "read_resp[w=%d][b=%d][r=%d] is valid(%d) mask(%d), tag=0x%x, offset=0x%x, type=%d, isExtend=%d, isRVC=%d\n",
259
          j.U, i.U, if2_realRow(i), if2_metaRead(j)(i).valid, if2_realMask(i), if2_metaRead(j)(i).tag, if2_dataRead(j)(i).offset, if2_metaRead(j)(i).btbType, if2_dataRead(j)(i).extended, if2_metaRead(j)(i).isRVC)
L
Lingrui98 已提交
260
        }
L
Lingrui98 已提交
261 262
      }
    }
263
    // e.g: baseBank == 5 => (5, 6,..., 15, 0, 1, 2, 3, 4)
264
    val bankIdxInOrder = VecInit((0 until BtbBanks).map(b => (if2_baseBank +& b.U)(log2Up(BtbBanks)-1,0)))
265

L
Lingrui98 已提交
266 267
    for (i <- 0 until BtbBanks) {
      val idx = bankIdxInOrder(i)
268
      XSDebug(validLatch && if2_bankHits(bankIdxInOrder(i)), "resp(%d): bank(%d) hits, tgt=%x, isRVC=%d, type=%d\n",
L
Lingrui98 已提交
269 270 271 272 273 274
        i.U, idx, io.resp.targets(i), io.resp.isRVC(i), io.resp.types(i))
    }
    XSDebug(updateValid, "update_req: cycle=%d, pc=0x%x, target=0x%x, misPred=%d, offset=%x, extended=%d, way=%d, bank=%d, row=0x%x\n",
      u.brInfo.debug_btb_cycle, u.pc, new_target, u.isMisPred, new_offset, new_extended, updateWay, updateBankIdx, updateRow)
    for (i <- 0 until BtbBanks) {
      // Conflict when not hit and allocating a valid entry
275
      val conflict = if2_metaRead(allocWays(i))(i).valid && !if2_bankHits(i)
L
Lingrui98 已提交
276 277 278 279
      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
L
Lingrui98 已提交
280
  }
281 282

  }
283
}