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