xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/ICacheMissUnit.scala (revision 1d8f4dcb81f46f3830f09013a9836143401cc425)
1*1d8f4dcbSJay/***************************************************************************************
2*1d8f4dcbSJay* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3*1d8f4dcbSJay* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*1d8f4dcbSJay*
5*1d8f4dcbSJay* XiangShan is licensed under Mulan PSL v2.
6*1d8f4dcbSJay* You can use this software according to the terms and conditions of the Mulan PSL v2.
7*1d8f4dcbSJay* You may obtain a copy of Mulan PSL v2 at:
8*1d8f4dcbSJay*          http://license.coscl.org.cn/MulanPSL2
9*1d8f4dcbSJay*
10*1d8f4dcbSJay* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11*1d8f4dcbSJay* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12*1d8f4dcbSJay* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*1d8f4dcbSJay*
14*1d8f4dcbSJay* See the Mulan PSL v2 for more details.
15*1d8f4dcbSJay***************************************************************************************/
16*1d8f4dcbSJay
17*1d8f4dcbSJaypackage xiangshan.frontend.icache
18*1d8f4dcbSJay
19*1d8f4dcbSJayimport chipsalliance.rocketchip.config.Parameters
20*1d8f4dcbSJayimport chisel3._
21*1d8f4dcbSJayimport chisel3.util._
22*1d8f4dcbSJayimport freechips.rocketchip.diplomacy.IdRange
23*1d8f4dcbSJayimport freechips.rocketchip.tilelink.ClientStates._
24*1d8f4dcbSJayimport freechips.rocketchip.tilelink.TLPermissions._
25*1d8f4dcbSJayimport freechips.rocketchip.tilelink._
26*1d8f4dcbSJayimport xiangshan._
27*1d8f4dcbSJayimport huancun.{AliasKey, DirtyKey}
28*1d8f4dcbSJayimport xiangshan.cache._
29*1d8f4dcbSJayimport utils._
30*1d8f4dcbSJay
31*1d8f4dcbSJay
32*1d8f4dcbSJayabstract class ICacheMissUnitModule(implicit p: Parameters) extends XSModule
33*1d8f4dcbSJay  with HasICacheParameters
34*1d8f4dcbSJay
35*1d8f4dcbSJayabstract class ICacheMissUnitBundle(implicit p: Parameters) extends XSBundle
36*1d8f4dcbSJay  with HasICacheParameters
37*1d8f4dcbSJay
38*1d8f4dcbSJayclass ICacheMissReq(implicit p: Parameters) extends ICacheBundle
39*1d8f4dcbSJay{
40*1d8f4dcbSJay    val paddr      = UInt(PAddrBits.W)
41*1d8f4dcbSJay    val vaddr      = UInt(VAddrBits.W)
42*1d8f4dcbSJay    val waymask   = UInt(nWays.W)
43*1d8f4dcbSJay    val coh       = new ClientMetadata
44*1d8f4dcbSJay    //val release   = ValidUndirectioned(new ReleaseReq)
45*1d8f4dcbSJay
46*1d8f4dcbSJay    def getVirSetIdx = get_idx(vaddr)
47*1d8f4dcbSJay    def getPhyTag    = get_phy_tag(paddr)
48*1d8f4dcbSJay}
49*1d8f4dcbSJay
50*1d8f4dcbSJay
51*1d8f4dcbSJayclass ICacheMissResp(implicit p: Parameters) extends ICacheBundle
52*1d8f4dcbSJay{
53*1d8f4dcbSJay    val data     = UInt(blockBits.W)
54*1d8f4dcbSJay}
55*1d8f4dcbSJay
56*1d8f4dcbSJayclass ICacheMissBundle(implicit p: Parameters) extends ICacheBundle{
57*1d8f4dcbSJay    val req       =   Vec(2, Flipped(DecoupledIO(new ICacheMissReq)))
58*1d8f4dcbSJay    val resp      =   Vec(2,ValidIO(new ICacheMissResp))
59*1d8f4dcbSJay    val flush     =   Input(Bool())
60*1d8f4dcbSJay}
61*1d8f4dcbSJay
62*1d8f4dcbSJay
63*1d8f4dcbSJayclass ICacheMissEntry(edge: TLEdgeOut, id: Int)(implicit p: Parameters) extends ICacheMissUnitModule
64*1d8f4dcbSJay  with MemoryOpConstants
65*1d8f4dcbSJay{
66*1d8f4dcbSJay  val io = IO(new Bundle {
67*1d8f4dcbSJay    val id = Input(UInt(log2Ceil(nMissEntries).W))
68*1d8f4dcbSJay
69*1d8f4dcbSJay    val req = Flipped(DecoupledIO(new ICacheMissReq))
70*1d8f4dcbSJay    val resp = ValidIO(new ICacheMissResp)
71*1d8f4dcbSJay
72*1d8f4dcbSJay    //tilelink channel
73*1d8f4dcbSJay    val mem_acquire = DecoupledIO(new TLBundleA(edge.bundle))
74*1d8f4dcbSJay    val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
75*1d8f4dcbSJay    val mem_finish = DecoupledIO(new TLBundleE(edge.bundle))
76*1d8f4dcbSJay
77*1d8f4dcbSJay    val meta_write = DecoupledIO(new ICacheMetaWriteBundle)
78*1d8f4dcbSJay    val data_write = DecoupledIO(new ICacheDataWriteBundle)
79*1d8f4dcbSJay
80*1d8f4dcbSJay//    val release    =  DecoupledIO(new ReleaseReq)
81*1d8f4dcbSJay//    val victimInfor = Output(new ICacheVictimInfor())
82*1d8f4dcbSJay//    val probeMerge  = Input(new ICacheVictimInfor)
83*1d8f4dcbSJay//    val probeMergeFix = Output(Bool())
84*1d8f4dcbSJay
85*1d8f4dcbSJay  })
86*1d8f4dcbSJay
87*1d8f4dcbSJay  /** default value for control signals */
88*1d8f4dcbSJay  io.resp := DontCare
89*1d8f4dcbSJay  io.mem_acquire.bits := DontCare
90*1d8f4dcbSJay  io.mem_grant.ready := true.B
91*1d8f4dcbSJay  io.meta_write.bits := DontCare
92*1d8f4dcbSJay  io.data_write.bits := DontCare
93*1d8f4dcbSJay
94*1d8f4dcbSJay  val s_idle :: s_send_release :: s_send_mem_aquire :: s_wait_mem_grant :: s_write_back :: s_send_grant_ack :: s_wait_resp :: Nil = Enum(7)
95*1d8f4dcbSJay  val state = RegInit(s_idle)
96*1d8f4dcbSJay
97*1d8f4dcbSJay  /** control logic transformation */
98*1d8f4dcbSJay  //request register
99*1d8f4dcbSJay  val req = Reg(new ICacheMissReq)
100*1d8f4dcbSJay  val req_idx = req.getVirSetIdx //virtual index
101*1d8f4dcbSJay  val req_tag = req.getPhyTag //physical tag
102*1d8f4dcbSJay  val req_waymask = req.waymask
103*1d8f4dcbSJay
104*1d8f4dcbSJay//  val victim_tag = get_phy_tag(req.release.bits.addr)
105*1d8f4dcbSJay//  val victim_idx = req_idx
106*1d8f4dcbSJay
107*1d8f4dcbSJay  val (_, _, refill_done, refill_address_inc) = edge.addr_inc(io.mem_grant)
108*1d8f4dcbSJay
109*1d8f4dcbSJay//  val needMergeProbe = (io.probeMerge.valid && state =/= s_idle && io.probeMerge.ptag === victim_tag && io.probeMerge.vidx === victim_idx)
110*1d8f4dcbSJay//
111*1d8f4dcbSJay//  //change release into a ProbeAck
112*1d8f4dcbSJay//  //WARNING: no change to param, default TtoN
113*1d8f4dcbSJay//  when(needMergeProbe && state === s_send_release){
114*1d8f4dcbSJay//    io.release.bits.voluntary := false.B
115*1d8f4dcbSJay//    io.release.bits.hasData   := true.B
116*1d8f4dcbSJay//  }
117*1d8f4dcbSJay//
118*1d8f4dcbSJay//  io.probeMergeFix := needMergeProbe && state === s_send_release
119*1d8f4dcbSJay
120*1d8f4dcbSJay  //cacheline register
121*1d8f4dcbSJay  //refullCycles: 8 for 64-bit bus bus and 2 for 256-bit
122*1d8f4dcbSJay  val readBeatCnt = Reg(UInt(log2Up(refillCycles).W))
123*1d8f4dcbSJay  val respDataReg = Reg(Vec(refillCycles, UInt(beatBits.W)))
124*1d8f4dcbSJay
125*1d8f4dcbSJay  //initial
126*1d8f4dcbSJay  io.resp.bits := DontCare
127*1d8f4dcbSJay  io.mem_acquire.bits := DontCare
128*1d8f4dcbSJay  io.mem_grant.ready := true.B
129*1d8f4dcbSJay  io.meta_write.bits := DontCare
130*1d8f4dcbSJay  io.data_write.bits := DontCare
131*1d8f4dcbSJay
132*1d8f4dcbSJay
133*1d8f4dcbSJay  io.req.ready := (state === s_idle)
134*1d8f4dcbSJay  io.mem_acquire.valid := (state === s_send_mem_aquire) //&& !io.flush
135*1d8f4dcbSJay
136*1d8f4dcbSJay  val grantack = RegEnable(edge.GrantAck(io.mem_grant.bits), io.mem_grant.fire())
137*1d8f4dcbSJay  val grant_param = Reg(UInt(TLPermissions.bdWidth.W))
138*1d8f4dcbSJay  val is_dirty = RegInit(false.B)
139*1d8f4dcbSJay  val is_grant = RegEnable(edge.isRequest(io.mem_grant.bits), io.mem_grant.fire())
140*1d8f4dcbSJay
141*1d8f4dcbSJay  val neddSendAck = RegInit(false.B)
142*1d8f4dcbSJay
143*1d8f4dcbSJay  //state change
144*1d8f4dcbSJay  switch(state) {
145*1d8f4dcbSJay    is(s_idle) {
146*1d8f4dcbSJay      when(io.req.fire()) {
147*1d8f4dcbSJay        readBeatCnt := 0.U
148*1d8f4dcbSJay        state := s_send_mem_aquire
149*1d8f4dcbSJay        req := io.req.bits
150*1d8f4dcbSJay      }
151*1d8f4dcbSJay    }
152*1d8f4dcbSJay
153*1d8f4dcbSJay    // memory request
154*1d8f4dcbSJay    is(s_send_mem_aquire) {
155*1d8f4dcbSJay      when(io.mem_acquire.fire()) {
156*1d8f4dcbSJay        state := s_wait_mem_grant
157*1d8f4dcbSJay      }
158*1d8f4dcbSJay    }
159*1d8f4dcbSJay
160*1d8f4dcbSJay    is(s_wait_mem_grant) {
161*1d8f4dcbSJay      when(edge.hasData(io.mem_grant.bits)) {
162*1d8f4dcbSJay        when(io.mem_grant.fire()) {
163*1d8f4dcbSJay          readBeatCnt := readBeatCnt + 1.U
164*1d8f4dcbSJay          respDataReg(readBeatCnt) := io.mem_grant.bits.data
165*1d8f4dcbSJay          grant_param := io.mem_grant.bits.param
166*1d8f4dcbSJay          is_dirty    := io.mem_grant.bits.echo.lift(DirtyKey).getOrElse(false.B)
167*1d8f4dcbSJay          when(readBeatCnt === (refillCycles - 1).U) {
168*1d8f4dcbSJay            assert(refill_done, "refill not done!")
169*1d8f4dcbSJay            state := s_write_back
170*1d8f4dcbSJay            neddSendAck := edge.isResponse(io.mem_grant.bits)
171*1d8f4dcbSJay          }
172*1d8f4dcbSJay        }
173*1d8f4dcbSJay      }
174*1d8f4dcbSJay    }
175*1d8f4dcbSJay
176*1d8f4dcbSJay    is(s_write_back) {
177*1d8f4dcbSJay      state := Mux(io.meta_write.fire() && io.data_write.fire(), Mux(neddSendAck, s_send_grant_ack, s_wait_resp), s_write_back)
178*1d8f4dcbSJay    }
179*1d8f4dcbSJay
180*1d8f4dcbSJay    is(s_send_grant_ack) {
181*1d8f4dcbSJay      when(io.mem_finish.fire()) {
182*1d8f4dcbSJay        state := s_wait_resp
183*1d8f4dcbSJay      }
184*1d8f4dcbSJay    }
185*1d8f4dcbSJay
186*1d8f4dcbSJay    is(s_wait_resp) {
187*1d8f4dcbSJay      io.resp.bits.data := respDataReg.asUInt
188*1d8f4dcbSJay      when(io.resp.fire()) {
189*1d8f4dcbSJay        state := s_idle
190*1d8f4dcbSJay      }
191*1d8f4dcbSJay    }
192*1d8f4dcbSJay  }
193*1d8f4dcbSJay
194*1d8f4dcbSJay  /** refill write and meta write */
195*1d8f4dcbSJay
196*1d8f4dcbSJay  /** update coh meta */
197*1d8f4dcbSJay  def missCohGen(param: UInt, dirty: Bool): UInt = {
198*1d8f4dcbSJay    MuxLookup(Cat(param, dirty), Nothing, Seq(
199*1d8f4dcbSJay      Cat(toB, false.B) -> Branch,
200*1d8f4dcbSJay      Cat(toB, true.B)  -> Branch,
201*1d8f4dcbSJay      Cat(toT, false.B) -> Trunk,
202*1d8f4dcbSJay      Cat(toT, true.B)  -> Dirty))
203*1d8f4dcbSJay  }
204*1d8f4dcbSJay
205*1d8f4dcbSJay  val miss_new_coh = ClientMetadata(missCohGen(grant_param, is_dirty))
206*1d8f4dcbSJay
207*1d8f4dcbSJay  io.meta_write.valid := (state === s_write_back)
208*1d8f4dcbSJay  io.meta_write.bits.generate(tag = req_tag, coh = miss_new_coh, idx = req_idx, waymask = req_waymask, bankIdx = req_idx(0))
209*1d8f4dcbSJay
210*1d8f4dcbSJay  io.data_write.valid := (state === s_write_back)
211*1d8f4dcbSJay  io.data_write.bits.generate(data = respDataReg.asUInt, idx = req_idx, waymask = req_waymask, bankIdx = req_idx(0))
212*1d8f4dcbSJay
213*1d8f4dcbSJay//  io.release.valid := req.release.valid && (state === s_send_release)
214*1d8f4dcbSJay//  io.release.bits  := req.release.bits
215*1d8f4dcbSJay//
216*1d8f4dcbSJay//  io.victimInfor.valid   := state =/= s_idle
217*1d8f4dcbSJay//  io.victimInfor.ptag    := req_tag
218*1d8f4dcbSJay//  io.victimInfor.vidx    := req_idx
219*1d8f4dcbSJay
220*1d8f4dcbSJay  /** Tilelink request for next level cache/memory */
221*1d8f4dcbSJay  val missCoh    = ClientMetadata(Nothing)
222*1d8f4dcbSJay  val grow_param = missCoh.onAccess(M_XRD)._2
223*1d8f4dcbSJay  val acquireBlock = edge.AcquireBlock(
224*1d8f4dcbSJay    fromSource = io.id,
225*1d8f4dcbSJay    toAddress = addrAlign(req.paddr, blockBytes, PAddrBits),
226*1d8f4dcbSJay    lgSize = (log2Up(cacheParams.blockBytes)).U,
227*1d8f4dcbSJay    growPermissions = grow_param
228*1d8f4dcbSJay  )._2
229*1d8f4dcbSJay  io.mem_acquire.bits := acquireBlock
230*1d8f4dcbSJay  // resolve cache alias by L2
231*1d8f4dcbSJay  io.mem_acquire.bits.user.lift(AliasKey).foreach(_ := req.vaddr(13, 12))
232*1d8f4dcbSJay  require(nSets <= 256) // icache size should not be more than 128KB
233*1d8f4dcbSJay
234*1d8f4dcbSJay  /** Grant ACK */
235*1d8f4dcbSJay  io.mem_finish.valid := (state === s_send_grant_ack) && is_grant
236*1d8f4dcbSJay  io.mem_finish.bits := grantack
237*1d8f4dcbSJay
238*1d8f4dcbSJay  //resp to ifu
239*1d8f4dcbSJay  io.resp.valid := state === s_wait_resp
240*1d8f4dcbSJay
241*1d8f4dcbSJay  XSPerfAccumulate(
242*1d8f4dcbSJay    "entryPenalty" + Integer.toString(id, 10),
243*1d8f4dcbSJay    BoolStopWatch(
244*1d8f4dcbSJay      start = io.req.fire(),
245*1d8f4dcbSJay      stop = io.resp.valid,
246*1d8f4dcbSJay      startHighPriority = true)
247*1d8f4dcbSJay  )
248*1d8f4dcbSJay  XSPerfAccumulate("entryReq" + Integer.toString(id, 10), io.req.fire())
249*1d8f4dcbSJay
250*1d8f4dcbSJay}
251*1d8f4dcbSJay
252*1d8f4dcbSJay
253*1d8f4dcbSJayclass ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheMissUnitModule
254*1d8f4dcbSJay{
255*1d8f4dcbSJay  val io = IO(new Bundle{
256*1d8f4dcbSJay    val req         = Vec(2, Flipped(DecoupledIO(new ICacheMissReq)))
257*1d8f4dcbSJay    val resp        = Vec(2, ValidIO(new ICacheMissResp))
258*1d8f4dcbSJay
259*1d8f4dcbSJay    val mem_acquire = DecoupledIO(new TLBundleA(edge.bundle))
260*1d8f4dcbSJay    val mem_grant   = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
261*1d8f4dcbSJay    val mem_finish  = DecoupledIO(new TLBundleE(edge.bundle))
262*1d8f4dcbSJay
263*1d8f4dcbSJay    val meta_write  = DecoupledIO(new ICacheMetaWriteBundle)
264*1d8f4dcbSJay    val data_write  = DecoupledIO(new ICacheDataWriteBundle)
265*1d8f4dcbSJay
266*1d8f4dcbSJay//    val release     = DecoupledIO(new ReleaseReq)
267*1d8f4dcbSJay
268*1d8f4dcbSJay//    val victimInfor = Vec(2, Output(new ICacheVictimInfor()))
269*1d8f4dcbSJay//    val probeMerge  = Flipped(ValidIO(new ICacheVictimInfor))
270*1d8f4dcbSJay  })
271*1d8f4dcbSJay  // assign default values to output signals
272*1d8f4dcbSJay  io.mem_grant.ready := false.B
273*1d8f4dcbSJay
274*1d8f4dcbSJay  val meta_write_arb = Module(new Arbiter(new ICacheMetaWriteBundle,  PortNumber))
275*1d8f4dcbSJay  val refill_arb     = Module(new Arbiter(new ICacheDataWriteBundle,  PortNumber))
276*1d8f4dcbSJay  //val release_arb    = Module(new Arbiter(new ReleaseReq,  PortNumber))
277*1d8f4dcbSJay
278*1d8f4dcbSJay  io.mem_grant.ready := true.B
279*1d8f4dcbSJay
280*1d8f4dcbSJay//  val probeMergeFix = VecInit(Seq.fill(2)(WireInit(false.B)))
281*1d8f4dcbSJay//
282*1d8f4dcbSJay//  val probeMerge = RegInit(0.U.asTypeOf(new ICacheVictimInfor))
283*1d8f4dcbSJay//  when(io.probeMerge.valid){
284*1d8f4dcbSJay//    probeMerge.ptag   := io.probeMerge.bits.ptag
285*1d8f4dcbSJay//    probeMerge.vidx   := io.probeMerge.bits.vidx
286*1d8f4dcbSJay//    probeMerge.valid  := true.B
287*1d8f4dcbSJay//  }
288*1d8f4dcbSJay//
289*1d8f4dcbSJay//  when(probeMergeFix.reduce(_||_)){
290*1d8f4dcbSJay//    probeMerge.valid := false.B
291*1d8f4dcbSJay//  }
292*1d8f4dcbSJay
293*1d8f4dcbSJay  val entries = (0 until 2) map { i =>
294*1d8f4dcbSJay    val entry = Module(new ICacheMissEntry(edge, i))
295*1d8f4dcbSJay
296*1d8f4dcbSJay    entry.io.id := i.U
297*1d8f4dcbSJay
298*1d8f4dcbSJay    // entry req
299*1d8f4dcbSJay    entry.io.req.valid := io.req(i).valid
300*1d8f4dcbSJay    entry.io.req.bits  := io.req(i).bits
301*1d8f4dcbSJay    io.req(i).ready    := entry.io.req.ready
302*1d8f4dcbSJay
303*1d8f4dcbSJay//    io.victimInfor(i)  := entry.io.victimInfor
304*1d8f4dcbSJay//    entry.io.probeMerge := probeMerge
305*1d8f4dcbSJay//
306*1d8f4dcbSJay//    probeMergeFix(i) := entry.io.probeMergeFix
307*1d8f4dcbSJay
308*1d8f4dcbSJay    // entry resp
309*1d8f4dcbSJay    meta_write_arb.io.in(i)     <>  entry.io.meta_write
310*1d8f4dcbSJay    refill_arb.io.in(i)         <>  entry.io.data_write
311*1d8f4dcbSJay    //release_arb.io.in(i)        <>  entry.io.release
312*1d8f4dcbSJay
313*1d8f4dcbSJay    entry.io.mem_grant.valid := false.B
314*1d8f4dcbSJay    entry.io.mem_grant.bits  := DontCare
315*1d8f4dcbSJay    when (io.mem_grant.bits.source === i.U) {
316*1d8f4dcbSJay      entry.io.mem_grant <> io.mem_grant
317*1d8f4dcbSJay    }
318*1d8f4dcbSJay
319*1d8f4dcbSJay    io.resp(i) <> entry.io.resp
320*1d8f4dcbSJay
321*1d8f4dcbSJay    XSPerfAccumulate(
322*1d8f4dcbSJay      "entryPenalty" + Integer.toString(i, 10),
323*1d8f4dcbSJay      BoolStopWatch(
324*1d8f4dcbSJay        start = entry.io.req.fire(),
325*1d8f4dcbSJay        stop = entry.io.resp.fire(),
326*1d8f4dcbSJay        startHighPriority = true)
327*1d8f4dcbSJay    )
328*1d8f4dcbSJay    XSPerfAccumulate("entryReq" + Integer.toString(i, 10), entry.io.req.fire())
329*1d8f4dcbSJay
330*1d8f4dcbSJay    entry
331*1d8f4dcbSJay  }
332*1d8f4dcbSJay
333*1d8f4dcbSJay  TLArbiter.lowest(edge, io.mem_acquire, entries.map(_.io.mem_acquire):_*)
334*1d8f4dcbSJay  TLArbiter.lowest(edge, io.mem_finish,  entries.map(_.io.mem_finish):_*)
335*1d8f4dcbSJay
336*1d8f4dcbSJay  io.meta_write     <> meta_write_arb.io.out
337*1d8f4dcbSJay  io.data_write     <> refill_arb.io.out
338*1d8f4dcbSJay  //io.release        <> release_arb.io.out
339*1d8f4dcbSJay
340*1d8f4dcbSJay  (0 until nWays).map{ w =>
341*1d8f4dcbSJay    XSPerfAccumulate("line_0_refill_way_" + Integer.toString(w, 10),  entries(0).io.meta_write.valid && OHToUInt(entries(0).io.meta_write.bits.waymask)  === w.U)
342*1d8f4dcbSJay    XSPerfAccumulate("line_1_refill_way_" + Integer.toString(w, 10),  entries(1).io.meta_write.valid && OHToUInt(entries(1).io.meta_write.bits.waymask)  === w.U)
343*1d8f4dcbSJay  }
344*1d8f4dcbSJay
345*1d8f4dcbSJay}
346*1d8f4dcbSJay
347*1d8f4dcbSJay
348*1d8f4dcbSJay
349