xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/ICache.scala (revision 51e45dbbf87325e45ff2af6ca86ed6c7eed04464)
1/***************************************************************************************
2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*
5* XiangShan is licensed under Mulan PSL v2.
6* You can use this software according to the terms and conditions of the Mulan PSL v2.
7* You may obtain a copy of Mulan PSL v2 at:
8*          http://license.coscl.org.cn/MulanPSL2
9*
10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*
14* See the Mulan PSL v2 for more details.
15***************************************************************************************/
16
17package  xiangshan.frontend.icache
18
19import chisel3._
20import chisel3.util._
21import freechips.rocketchip.diplomacy.{IdRange, LazyModule, LazyModuleImp}
22import freechips.rocketchip.tilelink._
23import freechips.rocketchip.util.BundleFieldBase
24import huancun.{AliasField, PrefetchField}
25import org.chipsalliance.cde.config.Parameters
26import utility._
27import utils._
28import xiangshan._
29import xiangshan.cache._
30import xiangshan.cache.mmu.TlbRequestIO
31import xiangshan.frontend._
32
33case class ICacheParameters(
34    nSets: Int = 256,
35    nWays: Int = 4,
36    rowBits: Int = 64,
37    nTLBEntries: Int = 32,
38    tagECC: Option[String] = None,
39    dataECC: Option[String] = None,
40    replacer: Option[String] = Some("random"),
41    nMissEntries: Int = 2,
42    nReleaseEntries: Int = 1,
43    nProbeEntries: Int = 2,
44    // fdip default config
45    enableICachePrefetch: Boolean = true,
46    prefetchToL1: Boolean = false,
47    prefetchPipeNum: Int = 1,
48    nPrefetchEntries: Int = 12,
49    nPrefBufferEntries: Int = 32,
50    maxIPFMoveConf: Int = 1, // temporary use small value to cause more "move" operation
51
52    nMMIOs: Int = 1,
53    blockBytes: Int = 64
54)extends L1CacheParameters {
55
56  val setBytes = nSets * blockBytes
57  val aliasBitsOpt = DCacheParameters().aliasBitsOpt //if(setBytes > pageSize) Some(log2Ceil(setBytes / pageSize)) else None
58  val reqFields: Seq[BundleFieldBase] = Seq(
59    PrefetchField(),
60    ReqSourceField()
61  ) ++ aliasBitsOpt.map(AliasField)
62  val echoFields: Seq[BundleFieldBase] = Nil
63  def tagCode: Code = Code.fromString(tagECC)
64  def dataCode: Code = Code.fromString(dataECC)
65  def replacement = ReplacementPolicy.fromString(replacer,nWays,nSets)
66}
67
68trait HasICacheParameters extends HasL1CacheParameters with HasInstrMMIOConst with HasIFUConst{
69  val cacheParams = icacheParameters
70  val dataCodeUnit = 16
71  val dataCodeUnitNum  = blockBits/dataCodeUnit
72
73  def highestIdxBit = log2Ceil(nSets) - 1
74  def encDataUnitBits   = cacheParams.dataCode.width(dataCodeUnit)
75  def dataCodeBits      = encDataUnitBits - dataCodeUnit
76  def dataCodeEntryBits = dataCodeBits * dataCodeUnitNum
77
78  val ICacheSets = cacheParams.nSets
79  val ICacheWays = cacheParams.nWays
80
81  val ICacheSameVPAddrLength = 12
82  val ReplaceIdWid = 5
83
84  val ICacheWordOffset = 0
85  val ICacheSetOffset = ICacheWordOffset + log2Up(blockBytes)
86  val ICacheAboveIndexOffset = ICacheSetOffset + log2Up(ICacheSets)
87  val ICacheTagOffset = ICacheAboveIndexOffset min ICacheSameVPAddrLength
88
89  def PortNumber = 2
90
91  def partWayNum = 2
92  def pWay = nWays/partWayNum
93
94  def enableICachePrefetch      = cacheParams.enableICachePrefetch
95  def prefetchToL1        = cacheParams.prefetchToL1
96  def prefetchPipeNum     = cacheParams.prefetchPipeNum
97  def nPrefetchEntries    = cacheParams.nPrefetchEntries
98  def nPrefBufferEntries  = cacheParams.nPrefBufferEntries
99  def maxIPFMoveConf      = cacheParams.maxIPFMoveConf
100
101  def getBits(num: Int) = log2Ceil(num).W
102
103
104  def generatePipeControl(lastFire: Bool, thisFire: Bool, thisFlush: Bool, lastFlush: Bool): Bool = {
105    val valid  = RegInit(false.B)
106    when(thisFlush)                    {valid  := false.B}
107      .elsewhen(lastFire && !lastFlush)  {valid  := true.B}
108      .elsewhen(thisFire)                 {valid  := false.B}
109    valid
110  }
111
112  def ResultHoldBypass[T<:Data](data: T, valid: Bool): T = {
113    Mux(valid, data, RegEnable(data, valid))
114  }
115
116  def holdReleaseLatch(valid: Bool, release: Bool, flush: Bool): Bool ={
117    val bit = RegInit(false.B)
118    when(flush)                   { bit := false.B  }
119      .elsewhen(valid && !release)  { bit := true.B   }
120      .elsewhen(release)            { bit := false.B  }
121    bit || valid
122  }
123
124  def blockCounter(block: Bool, flush: Bool, threshold: Int): Bool = {
125    val counter = RegInit(0.U(log2Up(threshold + 1).W))
126    when (block) { counter := counter + 1.U }
127    when (flush) { counter := 0.U}
128    counter > threshold.U
129  }
130
131  def InitQueue[T <: Data](entry: T, size: Int): Vec[T] ={
132    return RegInit(VecInit(Seq.fill(size)(0.U.asTypeOf(entry.cloneType))))
133  }
134
135  def getBlkPaddr(addr: UInt) = addr(PAddrBits-1, log2Ceil(blockBytes))
136
137  require(isPow2(nSets), s"nSets($nSets) must be pow2")
138  require(isPow2(nWays), s"nWays($nWays) must be pow2")
139}
140
141abstract class ICacheBundle(implicit p: Parameters) extends XSBundle
142  with HasICacheParameters
143
144abstract class ICacheModule(implicit p: Parameters) extends XSModule
145  with HasICacheParameters
146
147abstract class ICacheArray(implicit p: Parameters) extends XSModule
148  with HasICacheParameters
149
150class ICacheMetadata(implicit p: Parameters) extends ICacheBundle {
151  val tag = UInt(tagBits.W)
152}
153
154object ICacheMetadata {
155  def apply(tag: Bits)(implicit p: Parameters) = {
156    val meta = Wire(new ICacheMetadata)
157    meta.tag := tag
158    meta
159  }
160}
161
162
163class ICacheMetaArray()(implicit p: Parameters) extends ICacheArray
164{
165  def onReset = ICacheMetadata(0.U)
166  val metaBits = onReset.getWidth
167  val metaEntryBits = cacheParams.tagCode.width(metaBits)
168
169  val io=IO{new Bundle{
170    val write    = Flipped(DecoupledIO(new ICacheMetaWriteBundle))
171    val read     = Flipped(DecoupledIO(new ICacheReadBundle))
172    val readResp = Output(new ICacheMetaRespBundle)
173    val cacheOp  = Flipped(new L1CacheInnerOpIO) // customized cache op port
174    val fencei   = Input(Bool())
175  }}
176
177  io.read.ready := !io.write.valid
178
179  val port_0_read_0 = io.read.valid  && !io.read.bits.vSetIdx(0)(0)
180  val port_0_read_1 = io.read.valid  &&  io.read.bits.vSetIdx(0)(0)
181  val port_1_read_1  = io.read.valid &&  io.read.bits.vSetIdx(1)(0) && io.read.bits.isDoubleLine
182  val port_1_read_0  = io.read.valid && !io.read.bits.vSetIdx(1)(0) && io.read.bits.isDoubleLine
183
184  val port_0_read_0_reg = RegEnable(port_0_read_0, io.read.fire)
185  val port_0_read_1_reg = RegEnable(port_0_read_1, io.read.fire)
186  val port_1_read_1_reg = RegEnable(port_1_read_1, io.read.fire)
187  val port_1_read_0_reg = RegEnable(port_1_read_0, io.read.fire)
188
189  val bank_0_idx = Mux(port_0_read_0, io.read.bits.vSetIdx(0), io.read.bits.vSetIdx(1))
190  val bank_1_idx = Mux(port_0_read_1, io.read.bits.vSetIdx(0), io.read.bits.vSetIdx(1))
191  val bank_idx   = Seq(bank_0_idx, bank_1_idx)
192
193  val write_bank_0 = io.write.valid && !io.write.bits.bankIdx
194  val write_bank_1 = io.write.valid &&  io.write.bits.bankIdx
195
196  val write_meta_bits = Wire(UInt(metaEntryBits.W))
197
198  val tagArrays = (0 until 2) map { bank =>
199    val tagArray = Module(new SRAMTemplate(
200      UInt(metaEntryBits.W),
201      set=nSets/2,
202      way=nWays,
203      shouldReset = true,
204      holdRead = true,
205      singlePort = true
206    ))
207
208    //meta connection
209    if(bank == 0) {
210      tagArray.io.r.req.valid := port_0_read_0 || port_1_read_0
211      tagArray.io.r.req.bits.apply(setIdx=bank_0_idx(highestIdxBit,1))
212      tagArray.io.w.req.valid := write_bank_0
213      tagArray.io.w.req.bits.apply(data=write_meta_bits, setIdx=io.write.bits.virIdx(highestIdxBit,1), waymask=io.write.bits.waymask)
214    }
215    else {
216      tagArray.io.r.req.valid := port_0_read_1 || port_1_read_1
217      tagArray.io.r.req.bits.apply(setIdx=bank_1_idx(highestIdxBit,1))
218      tagArray.io.w.req.valid := write_bank_1
219      tagArray.io.w.req.bits.apply(data=write_meta_bits, setIdx=io.write.bits.virIdx(highestIdxBit,1), waymask=io.write.bits.waymask)
220    }
221
222    tagArray
223  }
224
225  val read_set_idx_next = RegEnable(io.read.bits.vSetIdx, io.read.fire)
226  val valid_array = RegInit(VecInit(Seq.fill(nWays)(0.U(nSets.W))))
227  val valid_metas = Wire(Vec(PortNumber, Vec(nWays, Bool())))
228  // valid read
229  (0 until PortNumber).foreach( i =>
230    (0 until nWays).foreach( way =>
231      valid_metas(i)(way) := valid_array(way)(read_set_idx_next(i))
232    ))
233  io.readResp.entryValid := valid_metas
234
235  io.read.ready := !io.write.valid && !io.fencei && tagArrays.map(_.io.r.req.ready).reduce(_&&_)
236
237  //Parity Decode
238  val read_metas = Wire(Vec(2,Vec(nWays,new ICacheMetadata())))
239  for((tagArray,i) <- tagArrays.zipWithIndex){
240    val read_meta_bits = tagArray.io.r.resp.asTypeOf(Vec(nWays,UInt(metaEntryBits.W)))
241    val read_meta_decoded = read_meta_bits.map{ way_bits => cacheParams.tagCode.decode(way_bits)}
242    val read_meta_wrong = read_meta_decoded.map{ way_bits_decoded => way_bits_decoded.error}
243    val read_meta_corrected = VecInit(read_meta_decoded.map{ way_bits_decoded => way_bits_decoded.corrected})
244    read_metas(i) := read_meta_corrected.asTypeOf(Vec(nWays,new ICacheMetadata()))
245    (0 until nWays).map{ w => io.readResp.errors(i)(w) := RegNext(read_meta_wrong(w)) && RegNext(RegNext(io.read.fire))}
246  }
247
248  //Parity Encode
249  val write = io.write.bits
250  write_meta_bits := cacheParams.tagCode.encode(ICacheMetadata(tag = write.phyTag).asUInt)
251
252  // valid write
253  val way_num = OHToUInt(io.write.bits.waymask)
254  when (io.write.valid) {
255    valid_array(way_num) := valid_array(way_num).bitSet(io.write.bits.virIdx, true.B)
256  }
257
258  XSPerfAccumulate("meta_refill_num", io.write.valid)
259
260  io.readResp.metaData <> DontCare
261  when(port_0_read_0_reg){
262    io.readResp.metaData(0) := read_metas(0)
263  }.elsewhen(port_0_read_1_reg){
264    io.readResp.metaData(0) := read_metas(1)
265  }
266
267  when(port_1_read_0_reg){
268    io.readResp.metaData(1) := read_metas(0)
269  }.elsewhen(port_1_read_1_reg){
270    io.readResp.metaData(1) := read_metas(1)
271  }
272
273
274  io.write.ready := true.B // TODO : has bug ? should be !io.cacheOp.req.valid
275  // deal with customized cache op
276  require(nWays <= 32)
277  io.cacheOp.resp.bits := DontCare
278  val cacheOpShouldResp = WireInit(false.B)
279  when(io.cacheOp.req.valid){
280    when(
281      CacheInstrucion.isReadTag(io.cacheOp.req.bits.opCode) ||
282      CacheInstrucion.isReadTagECC(io.cacheOp.req.bits.opCode)
283    ){
284      for (i <- 0 until 2) {
285        tagArrays(i).io.r.req.valid := true.B
286        tagArrays(i).io.r.req.bits.apply(setIdx = io.cacheOp.req.bits.index)
287      }
288      cacheOpShouldResp := true.B
289    }
290    when(CacheInstrucion.isWriteTag(io.cacheOp.req.bits.opCode)){
291      for (i <- 0 until 2) {
292        tagArrays(i).io.w.req.valid := true.B
293        tagArrays(i).io.w.req.bits.apply(
294          data = io.cacheOp.req.bits.write_tag_low,
295          setIdx = io.cacheOp.req.bits.index,
296          waymask = UIntToOH(io.cacheOp.req.bits.wayNum(4, 0))
297        )
298      }
299      cacheOpShouldResp := true.B
300    }
301    // TODO
302    // when(CacheInstrucion.isWriteTagECC(io.cacheOp.req.bits.opCode)){
303    //   for (i <- 0 until readPorts) {
304    //     array(i).io.ecc_write.valid := true.B
305    //     array(i).io.ecc_write.bits.idx := io.cacheOp.req.bits.index
306    //     array(i).io.ecc_write.bits.way_en := UIntToOH(io.cacheOp.req.bits.wayNum(4, 0))
307    //     array(i).io.ecc_write.bits.ecc := io.cacheOp.req.bits.write_tag_ecc
308    //   }
309    //   cacheOpShouldResp := true.B
310    // }
311  }
312  io.cacheOp.resp.valid := RegNext(io.cacheOp.req.valid && cacheOpShouldResp)
313  io.cacheOp.resp.bits.read_tag_low := Mux(io.cacheOp.resp.valid,
314    tagArrays(0).io.r.resp.asTypeOf(Vec(nWays, UInt(tagBits.W)))(io.cacheOp.req.bits.wayNum),
315    0.U
316  )
317  io.cacheOp.resp.bits.read_tag_ecc := DontCare // TODO
318  // TODO: deal with duplicated array
319
320  // fencei logic : reset valid_array
321  when (io.fencei) {
322    (0 until nWays).foreach( way =>
323      valid_array(way) := 0.U
324    )
325  }
326}
327
328
329
330class ICacheDataArray(implicit p: Parameters) extends ICacheArray
331{
332
333  def getECCFromEncUnit(encUnit: UInt) = {
334    require(encUnit.getWidth == encDataUnitBits)
335    if (encDataUnitBits == dataCodeUnit) {
336      0.U.asTypeOf(UInt(1.W))
337    } else {
338      encUnit(encDataUnitBits - 1, dataCodeUnit)
339    }
340  }
341
342  def getECCFromBlock(cacheblock: UInt) = {
343    // require(cacheblock.getWidth == blockBits)
344    VecInit((0 until dataCodeUnitNum).map { w =>
345      val unit = cacheblock(dataCodeUnit * (w + 1) - 1, dataCodeUnit * w)
346      getECCFromEncUnit(cacheParams.dataCode.encode(unit))
347    })
348  }
349
350  val io=IO{new Bundle{
351    val write    = Flipped(DecoupledIO(new ICacheDataWriteBundle))
352    val read     = Flipped(DecoupledIO(Vec(partWayNum, new ICacheReadBundle)))
353    val readResp = Output(new ICacheDataRespBundle)
354    val cacheOp  = Flipped(new L1CacheInnerOpIO) // customized cache op port
355  }}
356
357  val write_data_bits = Wire(UInt(blockBits.W))
358
359  val port_0_read_0_reg = RegEnable(io.read.valid && io.read.bits.head.port_0_read_0, io.read.fire)
360  val port_0_read_1_reg = RegEnable(io.read.valid && io.read.bits.head.port_0_read_1, io.read.fire)
361  val port_1_read_1_reg = RegEnable(io.read.valid && io.read.bits.head.port_1_read_1, io.read.fire)
362  val port_1_read_0_reg = RegEnable(io.read.valid && io.read.bits.head.port_1_read_0, io.read.fire)
363
364  val bank_0_idx_vec = io.read.bits.map(copy =>  Mux(io.read.valid && copy.port_0_read_0, copy.vSetIdx(0), copy.vSetIdx(1)))
365  val bank_1_idx_vec = io.read.bits.map(copy =>  Mux(io.read.valid && copy.port_0_read_1, copy.vSetIdx(0), copy.vSetIdx(1)))
366
367  val dataArrays = (0 until partWayNum).map{ i =>
368    val dataArray = Module(new ICachePartWayArray(
369      UInt(blockBits.W),
370      pWay,
371    ))
372
373    dataArray.io.read.req(0).valid :=  io.read.bits(i).read_bank_0 && io.read.valid
374    dataArray.io.read.req(0).bits.ridx := bank_0_idx_vec(i)(highestIdxBit,1)
375    dataArray.io.read.req(1).valid := io.read.bits(i).read_bank_1 && io.read.valid
376    dataArray.io.read.req(1).bits.ridx := bank_1_idx_vec(i)(highestIdxBit,1)
377
378
379    dataArray.io.write.valid         := io.write.valid
380    dataArray.io.write.bits.wdata    := write_data_bits
381    dataArray.io.write.bits.widx     := io.write.bits.virIdx(highestIdxBit,1)
382    dataArray.io.write.bits.wbankidx := io.write.bits.bankIdx
383    dataArray.io.write.bits.wmask    := io.write.bits.waymask.asTypeOf(Vec(partWayNum, Vec(pWay, Bool())))(i)
384
385    dataArray
386  }
387
388  val read_datas = Wire(Vec(2,Vec(nWays,UInt(blockBits.W) )))
389
390  (0 until PortNumber).map { port =>
391    (0 until nWays).map { w =>
392      read_datas(port)(w) := dataArrays(w / pWay).io.read.resp.rdata(port).asTypeOf(Vec(pWay, UInt(blockBits.W)))(w % pWay)
393    }
394  }
395
396  io.readResp.datas(0) := Mux( port_0_read_1_reg, read_datas(1) , read_datas(0))
397  io.readResp.datas(1) := Mux( port_1_read_0_reg, read_datas(0) , read_datas(1))
398
399  val write_data_code = Wire(UInt(dataCodeEntryBits.W))
400  val write_bank_0 = WireInit(io.write.valid && !io.write.bits.bankIdx)
401  val write_bank_1 = WireInit(io.write.valid &&  io.write.bits.bankIdx)
402
403  val bank_0_idx = bank_0_idx_vec.last
404  val bank_1_idx = bank_1_idx_vec.last
405
406  val codeArrays = (0 until 2) map { i =>
407    val codeArray = Module(new SRAMTemplate(
408      UInt(dataCodeEntryBits.W),
409      set=nSets/2,
410      way=nWays,
411      shouldReset = true,
412      holdRead = true,
413      singlePort = true
414    ))
415
416    if(i == 0) {
417      codeArray.io.r.req.valid := io.read.valid && io.read.bits.last.read_bank_0
418      codeArray.io.r.req.bits.apply(setIdx=bank_0_idx(highestIdxBit,1))
419      codeArray.io.w.req.valid := write_bank_0
420      codeArray.io.w.req.bits.apply(data=write_data_code, setIdx=io.write.bits.virIdx(highestIdxBit,1), waymask=io.write.bits.waymask)
421    }
422    else {
423      codeArray.io.r.req.valid := io.read.valid && io.read.bits.last.read_bank_1
424      codeArray.io.r.req.bits.apply(setIdx=bank_1_idx(highestIdxBit,1))
425      codeArray.io.w.req.valid := write_bank_1
426      codeArray.io.w.req.bits.apply(data=write_data_code, setIdx=io.write.bits.virIdx(highestIdxBit,1), waymask=io.write.bits.waymask)
427    }
428
429    codeArray
430  }
431
432  io.read.ready := !io.write.valid &&
433                    dataArrays.map(_.io.read.req.map(_.ready).reduce(_&&_)).reduce(_&&_) &&
434                    codeArrays.map(_.io.r.req.ready).reduce(_ && _)
435
436  //Parity Decode
437  val read_codes = Wire(Vec(2,Vec(nWays,UInt(dataCodeEntryBits.W) )))
438  for(((dataArray,codeArray),i) <- dataArrays.zip(codeArrays).zipWithIndex){
439    read_codes(i) := codeArray.io.r.resp.asTypeOf(Vec(nWays,UInt(dataCodeEntryBits.W)))
440  }
441
442  //Parity Encode
443  val write = io.write.bits
444  val write_data = WireInit(write.data)
445  write_data_code := getECCFromBlock(write_data).asUInt
446  write_data_bits := write_data
447
448  io.readResp.codes(0) := Mux( port_0_read_1_reg, read_codes(1) , read_codes(0))
449  io.readResp.codes(1) := Mux( port_1_read_0_reg, read_codes(0) , read_codes(1))
450
451  io.write.ready := true.B
452
453  // deal with customized cache op
454  require(nWays <= 32)
455  io.cacheOp.resp.bits := DontCare
456  io.cacheOp.resp.valid := false.B
457  val cacheOpShouldResp = WireInit(false.B)
458  val dataresp = Wire(Vec(nWays,UInt(blockBits.W) ))
459  dataresp := DontCare
460  when(io.cacheOp.req.valid){
461    when(
462      CacheInstrucion.isReadData(io.cacheOp.req.bits.opCode)
463    ){
464      for (i <- 0 until partWayNum) {
465        dataArrays(i).io.read.req.zipWithIndex.map{ case(port,i) =>
466          if(i ==0) port.valid     := !io.cacheOp.req.bits.bank_num(0)
467          else      port.valid     :=  io.cacheOp.req.bits.bank_num(0)
468          port.bits.ridx := io.cacheOp.req.bits.index(highestIdxBit,1)
469        }
470      }
471      cacheOpShouldResp := dataArrays.head.io.read.req.map(_.fire).reduce(_||_)
472      dataresp :=Mux(io.cacheOp.req.bits.bank_num(0).asBool,  read_datas(1),  read_datas(0))
473    }
474    when(CacheInstrucion.isWriteData(io.cacheOp.req.bits.opCode)){
475      for (i <- 0 until partWayNum) {
476        dataArrays(i).io.write.valid := true.B
477        dataArrays(i).io.write.bits.wdata := io.cacheOp.req.bits.write_data_vec.asTypeOf(write_data.cloneType)
478        dataArrays(i).io.write.bits.wbankidx := io.cacheOp.req.bits.bank_num(0)
479        dataArrays(i).io.write.bits.widx := io.cacheOp.req.bits.index(highestIdxBit,1)
480        dataArrays(i).io.write.bits.wmask  := UIntToOH(io.cacheOp.req.bits.wayNum(4, 0)).asTypeOf(Vec(partWayNum, Vec(pWay, Bool())))(i)
481      }
482      cacheOpShouldResp := true.B
483    }
484  }
485
486  io.cacheOp.resp.valid := RegNext(cacheOpShouldResp)
487  val numICacheLineWords = blockBits / 64
488  require(blockBits >= 64 && isPow2(blockBits))
489  for (wordIndex <- 0 until numICacheLineWords) {
490    io.cacheOp.resp.bits.read_data_vec(wordIndex) := dataresp(io.cacheOp.req.bits.wayNum(4, 0))(64*(wordIndex+1)-1, 64*wordIndex)
491  }
492
493}
494
495
496class ICacheIO(implicit p: Parameters) extends ICacheBundle
497{
498  val hartId = Input(UInt(8.W))
499  val prefetch    = Flipped(new FtqPrefechBundle)
500  val stop        = Input(Bool())
501  val fetch       = new ICacheMainPipeBundle
502  val toIFU       = Output(Bool())
503  val pmp         = Vec(PortNumber + prefetchPipeNum, new ICachePMPBundle)
504  val itlb        = Vec(PortNumber + prefetchPipeNum, new TlbRequestIO)
505  val perfInfo    = Output(new ICachePerfInfo)
506  val error       = new L1CacheErrorInfo
507  /* Cache Instruction */
508  val csr         = new L1CacheToCsrIO
509  /* CSR control signal */
510  val csr_pf_enable = Input(Bool())
511  val csr_parity_enable = Input(Bool())
512  val fencei      = Input(Bool())
513}
514
515class ICache()(implicit p: Parameters) extends LazyModule with HasICacheParameters {
516  override def shouldBeInlined: Boolean = false
517
518  val clientParameters = TLMasterPortParameters.v1(
519    Seq(TLMasterParameters.v1(
520      name = "icache",
521      sourceId = IdRange(0, cacheParams.nMissEntries + 1),
522    )),
523    requestFields = cacheParams.reqFields,
524    echoFields = cacheParams.echoFields
525  )
526
527  val clientNode = TLClientNode(Seq(clientParameters))
528
529  lazy val module = new ICacheImp(this)
530}
531
532class ICacheImp(outer: ICache) extends LazyModuleImp(outer) with HasICacheParameters with HasPerfEvents {
533  val io = IO(new ICacheIO)
534
535  println("ICache:")
536  println("  ICacheSets: "          + cacheParams.nSets)
537  println("  ICacheWays: "          + cacheParams.nWays)
538  println("  ICacheBanks: "         + PortNumber)
539
540  println("  enableICachePrefetch:     " + cacheParams.enableICachePrefetch)
541  println("  prefetchToL1:       " + cacheParams.prefetchToL1)
542  println("  prefetchPipeNum:    " + cacheParams.prefetchPipeNum)
543  println("  nPrefetchEntries:   " + cacheParams.nPrefetchEntries)
544  println("  nPrefBufferEntries: " + cacheParams.nPrefBufferEntries)
545  println("  maxIPFMoveConf:     " + cacheParams.maxIPFMoveConf)
546
547  val (bus, edge) = outer.clientNode.out.head
548
549  val metaArray         = Module(new ICacheMetaArray)
550  val dataArray         = Module(new ICacheDataArray)
551  val prefetchMetaArray = Module(new ICacheBankedMetaArray(prefetchPipeNum)) // need add 1 port for IPF filter
552  val mainPipe          = Module(new ICacheMainPipe)
553  val missUnit          = Module(new ICacheMissUnit(edge))
554  val fdipPrefetch      = Module(new FDIPPrefetch(edge))
555
556  fdipPrefetch.io.hartId              := io.hartId
557  fdipPrefetch.io.fencei              := io.fencei
558  fdipPrefetch.io.ftqReq              <> io.prefetch
559  fdipPrefetch.io.metaReadReq         <> prefetchMetaArray.io.read(0)
560  fdipPrefetch.io.metaReadResp        <> prefetchMetaArray.io.readResp(0)
561  fdipPrefetch.io.ICacheMissUnitInfo  <> missUnit.io.ICacheMissUnitInfo
562  fdipPrefetch.io.ICacheMainPipeInfo  <> mainPipe.io.ICacheMainPipeInfo
563  fdipPrefetch.io.IPFBufferRead       <> mainPipe.io.IPFBufferRead
564  fdipPrefetch.io.IPFReplacer         <> mainPipe.io.IPFReplacer
565  fdipPrefetch.io.PIQRead             <> mainPipe.io.PIQRead
566  fdipPrefetch.io.metaWrite           <> DontCare
567  fdipPrefetch.io.dataWrite           <> DontCare
568
569  // Meta Array. Priority: missUnit > fdipPrefetch
570  if (prefetchToL1) {
571    val meta_write_arb  = Module(new Arbiter(new ICacheMetaWriteBundle(),  2))
572    meta_write_arb.io.in(0)     <> missUnit.io.meta_write
573    meta_write_arb.io.in(1)     <> fdipPrefetch.io.metaWrite
574    meta_write_arb.io.out       <> metaArray.io.write
575    // prefetch Meta Array. Connect meta_write_arb to ensure the data is same as metaArray
576    prefetchMetaArray.io.write <> meta_write_arb.io.out
577  } else {
578    missUnit.io.meta_write <> metaArray.io.write
579    missUnit.io.meta_write <> prefetchMetaArray.io.write
580    // ensure together wirte to metaArray and prefetchMetaArray
581    missUnit.io.meta_write.ready := metaArray.io.write.ready && prefetchMetaArray.io.write.ready
582  }
583
584  // Data Array. Priority: missUnit > fdipPrefetch
585  if (prefetchToL1) {
586    val data_write_arb = Module(new Arbiter(new ICacheDataWriteBundle(), 2))
587    data_write_arb.io.in(0)     <> missUnit.io.data_write
588    data_write_arb.io.in(1)     <> fdipPrefetch.io.dataWrite
589    data_write_arb.io.out       <> dataArray.io.write
590  } else {
591    missUnit.io.data_write <> dataArray.io.write
592  }
593
594  mainPipe.io.dataArray.toIData     <> dataArray.io.read
595  mainPipe.io.dataArray.fromIData   <> dataArray.io.readResp
596  mainPipe.io.metaArray.toIMeta     <> metaArray.io.read
597  mainPipe.io.metaArray.fromIMeta   <> metaArray.io.readResp
598  mainPipe.io.metaArray.fromIMeta   <> metaArray.io.readResp
599  mainPipe.io.respStall             := io.stop
600  mainPipe.io.csr_parity_enable     := io.csr_parity_enable
601  mainPipe.io.hartId                := io.hartId
602
603  io.pmp(0) <> mainPipe.io.pmp(0)
604  io.pmp(1) <> mainPipe.io.pmp(1)
605  io.pmp(2) <> fdipPrefetch.io.pmp
606
607  io.itlb(0) <> mainPipe.io.itlb(0)
608  io.itlb(1) <> mainPipe.io.itlb(1)
609  io.itlb(2) <> fdipPrefetch.io.iTLBInter
610
611  //notify IFU that Icache pipeline is available
612  io.toIFU := mainPipe.io.fetch.req.ready
613  io.perfInfo := mainPipe.io.perfInfo
614
615  io.fetch.resp     <>    mainPipe.io.fetch.resp
616  io.fetch.topdownIcacheMiss := mainPipe.io.fetch.topdownIcacheMiss
617  io.fetch.topdownItlbMiss   := mainPipe.io.fetch.topdownItlbMiss
618
619  for(i <- 0 until PortNumber){
620    missUnit.io.req(i)           <>   mainPipe.io.mshr(i).toMSHR
621    mainPipe.io.mshr(i).fromMSHR <>   missUnit.io.resp(i)
622  }
623
624  missUnit.io.hartId       := io.hartId
625  missUnit.io.fencei       := io.fencei
626  missUnit.io.fdip_acquire <> fdipPrefetch.io.mem_acquire
627  missUnit.io.fdip_grant   <> fdipPrefetch.io.mem_grant
628
629  bus.b.ready := false.B
630  bus.c.valid := false.B
631  bus.c.bits  := DontCare
632  bus.e.valid := false.B
633  bus.e.bits  := DontCare
634
635  bus.a <> missUnit.io.mem_acquire
636
637  // connect bus d
638  missUnit.io.mem_grant.valid := false.B
639  missUnit.io.mem_grant.bits  := DontCare
640
641  //Parity error port
642  val errors = mainPipe.io.errors
643  io.error <> RegNext(Mux1H(errors.map(e => e.valid -> e)))
644
645
646  mainPipe.io.fetch.req <> io.fetch.req
647  bus.d.ready := false.B
648  missUnit.io.mem_grant <> bus.d
649
650  // fencei connect
651  metaArray.io.fencei := io.fencei
652  prefetchMetaArray.io.fencei := io.fencei
653
654  val perfEvents = Seq(
655    ("icache_miss_cnt  ", false.B),
656    ("icache_miss_penty", BoolStopWatch(start = false.B, stop = false.B || false.B, startHighPriority = true)),
657  )
658  generatePerfEvent()
659
660  // Customized csr cache op support
661  val cacheOpDecoder = Module(new CSRCacheOpDecoder("icache", CacheInstrucion.COP_ID_ICACHE))
662  cacheOpDecoder.io.csr <> io.csr
663  dataArray.io.cacheOp.req := cacheOpDecoder.io.cache.req
664  metaArray.io.cacheOp.req := cacheOpDecoder.io.cache.req
665  prefetchMetaArray.io.cacheOp.req := cacheOpDecoder.io.cache.req
666  cacheOpDecoder.io.cache.resp.valid :=
667    dataArray.io.cacheOp.resp.valid ||
668    metaArray.io.cacheOp.resp.valid
669  cacheOpDecoder.io.cache.resp.bits := Mux1H(List(
670    dataArray.io.cacheOp.resp.valid -> dataArray.io.cacheOp.resp.bits,
671    metaArray.io.cacheOp.resp.valid -> metaArray.io.cacheOp.resp.bits,
672  ))
673  cacheOpDecoder.io.error := io.error
674  assert(!((dataArray.io.cacheOp.resp.valid +& metaArray.io.cacheOp.resp.valid) > 1.U))
675}
676
677class ICachePartWayReadBundle[T <: Data](gen: T, pWay: Int)(implicit p: Parameters)
678  extends ICacheBundle
679{
680  val req = Flipped(Vec(PortNumber, Decoupled(new Bundle{
681    val ridx = UInt((log2Ceil(nSets) - 1).W)
682  })))
683  val resp = Output(new Bundle{
684    val rdata  = Vec(PortNumber,Vec(pWay, gen))
685  })
686}
687
688class ICacheWriteBundle[T <: Data](gen: T, pWay: Int)(implicit p: Parameters)
689  extends ICacheBundle
690{
691  val wdata = gen
692  val widx = UInt((log2Ceil(nSets) - 1).W)
693  val wbankidx = Bool()
694  val wmask = Vec(pWay, Bool())
695}
696
697class ICachePartWayArray[T <: Data](gen: T, pWay: Int)(implicit p: Parameters) extends ICacheArray
698{
699
700  //including part way data
701  val io = IO{new Bundle {
702    val read      = new  ICachePartWayReadBundle(gen,pWay)
703    val write     = Flipped(ValidIO(new ICacheWriteBundle(gen, pWay)))
704  }}
705
706  io.read.req.map(_.ready := !io.write.valid)
707
708  val srams = (0 until PortNumber) map { bank =>
709    val sramBank = Module(new SRAMTemplate(
710      gen,
711      set=nSets/2,
712      way=pWay,
713      shouldReset = true,
714      holdRead = true,
715      singlePort = true
716    ))
717
718    sramBank.io.r.req.valid := io.read.req(bank).valid
719    sramBank.io.r.req.bits.apply(setIdx= io.read.req(bank).bits.ridx)
720
721    if(bank == 0) sramBank.io.w.req.valid := io.write.valid && !io.write.bits.wbankidx
722    else sramBank.io.w.req.valid := io.write.valid && io.write.bits.wbankidx
723    sramBank.io.w.req.bits.apply(data=io.write.bits.wdata, setIdx=io.write.bits.widx, waymask=io.write.bits.wmask.asUInt)
724
725    sramBank
726  }
727
728  io.read.req.map(_.ready := !io.write.valid && srams.map(_.io.r.req.ready).reduce(_&&_))
729
730  io.read.resp.rdata := VecInit(srams.map(bank => bank.io.r.resp.asTypeOf(Vec(pWay,gen))))
731
732}
733