Brq.scala 6.0 KB
Newer Older
1 2 3 4 5
package xiangshan.backend.brq

import chisel3._
import chisel3.util._
import xiangshan._
L
LinJiawei 已提交
6
import xiangshan.utils._
7 8


L
LinJiawei 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
class BrqPtr extends XSBundle {

  val flag = Bool()
  val value = UInt(BrTagWidth.W)

  final def + (inc: Bool): BrqPtr = {
    Mux(inc && (value === (BrqSize-1).U),
      BrqPtr(!flag, 0.U),
      BrqPtr(flag, value + inc)
    )
  }

  final def === (that: BrqPtr): Bool = {
    (this.value===that.value) && (this.flag===that.flag)
  }

25 26
  // this.age < that.age
  final def < (that: BrqPtr): Bool = {
L
LinJiawei 已提交
27 28 29 30 31 32
    Mux(this.flag === that.flag,
      this.value > that.value,
      this.value < that.value
    )
  }

33
  def needBrFlush(redirectTag: BrqPtr): Bool = this < redirectTag
L
LinJiawei 已提交
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

  def needFlush(redirect: Valid[Redirect]): Bool = {
    redirect.valid && (redirect.bits.isException || needBrFlush(redirect.bits.brTag))
  }

  override def toPrintable: Printable = p"f:$flag v:$value"

}

object BrqPtr {
  def apply(f: Bool, v: UInt): BrqPtr = {
    val ptr = Wire(new BrqPtr)
    ptr.flag := f
    ptr.value := v
    ptr
  }
}

L
LinJiawei 已提交
52 53 54 55
class BrqIO extends XSBundle{
  // interrupt/exception happen, flush Brq
  val roqRedirect = Input(Valid(new Redirect))
  // receive branch/jump calculated target
L
LinJiawei 已提交
56
  val exuRedirect = Vec(exuParameters.AluCnt + exuParameters.JmpCnt, Flipped(ValidIO(new ExuOutput)))
L
LinJiawei 已提交
57 58 59 60 61 62 63 64 65
  // from decode, branch insts enq
  val enqReqs = Vec(DecodeWidth, Flipped(DecoupledIO(new CfCtrl)))
  // to decode
  val brTags = Output(Vec(DecodeWidth, new BrqPtr))
  // to roq
  val out = ValidIO(new ExuOutput)
  // misprediction, flush pipeline
  val redirect = Output(Valid(new Redirect))
}
66

L
LinJiawei 已提交
67
class Brq extends XSModule {
L
LinJiawei 已提交
68 69 70 71
  val io = IO(new BrqIO)

  def redirctWindowSize: Int = BrqSize/2
  require(redirctWindowSize <= BrqSize && redirctWindowSize > 0)
L
LinJiawei 已提交
72

73
  class BrqEntry extends Bundle {
L
LinJiawei 已提交
74
    val ptrFlag = Bool()
75
    val npc = UInt(VAddrBits.W)
L
LinJiawei 已提交
76
    val misPred = Bool()
L
LinJiawei 已提交
77
    val exuOut = new ExuOutput
78 79
  }

80 81
  val s_idle :: s_wb :: s_commited :: Nil  =
    List.tabulate(3)(i => (1 << i).U(3.W).asTypeOf(new StateQueueEntry))
L
LinJiawei 已提交
82

83 84 85 86
  class StateQueueEntry extends Bundle{
    val isCommit = Bool()
    val isWb = Bool()
    val isIdle = Bool()
L
LinJiawei 已提交
87 88
  }

89
  val brQueue = Reg(Vec(BrqSize, new BrqEntry))
90
  val stateQueue = RegInit(VecInit(Seq.fill(BrqSize)(s_idle)))
L
LinJiawei 已提交
91

L
LinJiawei 已提交
92
  val headPtr, tailPtr = RegInit(BrqPtr(false.B, 0.U))
L
LinJiawei 已提交
93

L
LinJiawei 已提交
94 95
  def isEmpty(ptr1: BrqPtr, ptr2: BrqPtr): Bool = ptr1 === ptr2
  def isFull(ptr1: BrqPtr, ptr2: BrqPtr): Bool = (ptr1.flag=/=ptr2.flag) && (ptr1.value===ptr2.value)
L
LinJiawei 已提交
96 97 98


  // dequeue
L
LinJiawei 已提交
99
  val headIdx = headPtr.value
L
LinJiawei 已提交
100
  var commitIdx = WireInit(headIdx)
101 102 103 104 105 106

  def needCheckNext(idx: UInt): Bool = {
    (stateQueue(idx).isWb && !brQueue(idx).misPred) || stateQueue(idx).isCommit
  }

  var checkNext = WireInit(needCheckNext(headIdx))
L
LinJiawei 已提交
107 108 109

  for(i <- 1 until redirctWindowSize){
    val idx = commitIdx + i.U
110
    val commitThis = checkNext && stateQueue(idx).isWb && brQueue(idx).misPred
L
LinJiawei 已提交
111 112 113 114
    commitIdx = Mux(commitThis,
      idx,
      commitIdx
    )
115
    checkNext = checkNext && needCheckNext(idx)
L
LinJiawei 已提交
116 117 118
  }

  val commitIsHead = commitIdx===headIdx
119 120
  val deqValid = !stateQueue(headIdx).isIdle && commitIsHead
  val commitValid = stateQueue(commitIdx).isWb
L
LinJiawei 已提交
121 122 123 124 125
  val commitEntry = brQueue(commitIdx)


  XSDebug(p"headIdx:$headIdx commitIdx:$commitIdx\n")
  XSDebug(p"headPtr:$headPtr tailPtr:$tailPtr\n")
126 127 128 129 130 131 132
  XSDebug("")
  stateQueue.map(s =>{
    XSDebug(false, s.isIdle, "-")
    XSDebug(false, s.isWb, "w")
    XSDebug(false, s.isCommit, "c")
  })
  XSDebug(false, true.B, "\n")
L
LinJiawei 已提交
133 134

  val headPtrNext = WireInit(headPtr + deqValid)
135 136 137 138 139
  stateQueue(commitIdx):= Mux(deqValid,
    s_idle,
    Mux(commitValid,
      s_commited,
      stateQueue(commitIdx)
L
LinJiawei 已提交
140 141 142
    )
  )

L
LinJiawei 已提交
143
  headPtr := headPtrNext
L
LinJiawei 已提交
144 145 146 147 148 149 150
  io.redirect.valid := commitValid && commitEntry.misPred
  io.redirect.bits := commitEntry.exuOut.redirect
  io.out.valid := commitValid
  io.out.bits := commitEntry.exuOut
  XSInfo(io.out.valid,
    p"commit branch to roq, mispred:${io.redirect.valid} pc=${Hexadecimal(io.out.bits.uop.cf.pc)}\n"
  )
L
LinJiawei 已提交
151 152 153 154

  // branch insts enq
  var full = WireInit(isFull(headPtrNext, tailPtr))
  var tailPtrNext = WireInit(tailPtr)
L
LinJiawei 已提交
155
  for((enq, brTag) <- io.enqReqs.zip(io.brTags)){
L
LinJiawei 已提交
156
    enq.ready := !full
L
LinJiawei 已提交
157
    brTag := tailPtrNext
158
    // TODO: check rvc and use predict npc
L
LinJiawei 已提交
159 160 161 162
    when(enq.fire()){
      brQueue(tailPtrNext.value).npc := enq.bits.cf.pc + 4.U
      brQueue(tailPtrNext.value).ptrFlag := tailPtrNext.flag
    }
L
LinJiawei 已提交
163 164 165 166 167 168 169
    tailPtrNext = tailPtrNext + enq.fire()
    full = isFull(tailPtrNext, headPtrNext)
  }
  tailPtr := tailPtrNext

  // exu write back
  for(exuWb <- io.exuRedirect){
L
LinJiawei 已提交
170
    when(exuWb.valid){
L
LinJiawei 已提交
171 172 173
      val wbIdx = exuWb.bits.redirect.brTag.value
      XSInfo(
        p"exu write back: brTag:${exuWb.bits.redirect.brTag}" +
174
          p" pc=${Hexadecimal(exuWb.bits.uop.cf.pc)} pnpc=${Hexadecimal(brQueue(wbIdx).npc)} target=${Hexadecimal(exuWb.bits.redirect.target)}\n"
L
LinJiawei 已提交
175
      )
176
      stateQueue(wbIdx) := s_wb
L
LinJiawei 已提交
177 178
      brQueue(wbIdx).exuOut := exuWb.bits
      brQueue(wbIdx).misPred := brQueue(wbIdx).npc =/= exuWb.bits.redirect.target
L
LinJiawei 已提交
179 180 181
    }
  }

L
LinJiawei 已提交
182 183
  when(io.roqRedirect.valid){
    // exception
184
    stateQueue.foreach(_ := s_idle)
L
LinJiawei 已提交
185 186 187 188 189 190 191
    headPtr := BrqPtr(false.B, 0.U)
    tailPtr := BrqPtr(false.B, 0.U)
  }.elsewhen(io.redirect.valid){
    // misprediction
    stateQueue.zipWithIndex.foreach({case(s, i) =>
      val ptr = BrqPtr(brQueue(i).ptrFlag, i.U)
      when(ptr.needBrFlush(io.redirect.bits.brTag)){
192
        s := s_idle
L
LinJiawei 已提交
193 194 195
      }
    })
    tailPtr := io.redirect.bits.brTag + true.B
L
LinJiawei 已提交
196
  }
L
LinJiawei 已提交
197 198 199 200 201 202 203 204 205 206




  // Debug info
  val debug_roq_redirect = io.roqRedirect.valid
  val debug_brq_redirect = io.redirect.valid && !debug_roq_redirect
  val debug_normal_mode = !(debug_roq_redirect || debug_brq_redirect)

  for(i <- 0 until DecodeWidth){
L
LinJiawei 已提交
207
    XSDebug(
L
LinJiawei 已提交
208 209
      debug_normal_mode,
      p"enq v:${io.enqReqs(i).valid} rdy:${io.enqReqs(i).ready} pc:${Hexadecimal(io.enqReqs(i).bits.cf.pc)}" +
L
LinJiawei 已提交
210
        p" brTag:${io.brTags(i)}\n"
L
LinJiawei 已提交
211 212 213 214
    )
  }

  XSInfo(debug_roq_redirect, "roq redirect, flush brq\n")
L
LinJiawei 已提交
215
  XSInfo(debug_brq_redirect, p"brq redirect, target:${Hexadecimal(io.redirect.bits.target)} flptr:${io.redirect.bits.freelistAllocPtr}\n")
216
}