xref: /XiangShan/src/main/scala/xiangshan/frontend/WrBypass.scala (revision cf7d6b7a1a781c73aeb87de112de2e7fe5ea3b7c)
1569b279fSLingrui98/***************************************************************************************
2569b279fSLingrui98* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3569b279fSLingrui98* Copyright (c) 2020-2021 Peng Cheng Laboratory
4569b279fSLingrui98*
5569b279fSLingrui98* XiangShan is licensed under Mulan PSL v2.
6569b279fSLingrui98* You can use this software according to the terms and conditions of the Mulan PSL v2.
7569b279fSLingrui98* You may obtain a copy of Mulan PSL v2 at:
8569b279fSLingrui98*          http://license.coscl.org.cn/MulanPSL2
9569b279fSLingrui98*
10569b279fSLingrui98* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11569b279fSLingrui98* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12569b279fSLingrui98* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13569b279fSLingrui98*
14569b279fSLingrui98* See the Mulan PSL v2 for more details.
15569b279fSLingrui98***************************************************************************************/
16569b279fSLingrui98package xiangshan.frontend
17569b279fSLingrui98
18569b279fSLingrui98import chisel3._
19569b279fSLingrui98import chisel3.util._
20*cf7d6b7aSMuziimport org.chipsalliance.cde.config.Parameters
213c02ee8fSwakafaimport utility._
22*cf7d6b7aSMuziimport utils._
23*cf7d6b7aSMuziimport xiangshan._
2476e02f07SLingrui98import xiangshan.cache.mmu.CAMTemplate
25569b279fSLingrui98
26*cf7d6b7aSMuziclass WrBypass[T <: Data](
27*cf7d6b7aSMuzi    gen:            T,
28*cf7d6b7aSMuzi    val numEntries: Int,
29*cf7d6b7aSMuzi    val idxWidth:   Int,
30*cf7d6b7aSMuzi    val numWays:    Int = 1,
31*cf7d6b7aSMuzi    val tagWidth:   Int = 0,
32*cf7d6b7aSMuzi    val extraPort:  Option[Boolean] = None
33*cf7d6b7aSMuzi)(implicit p: Parameters) extends XSModule {
34569b279fSLingrui98  require(numEntries >= 0)
35569b279fSLingrui98  require(idxWidth > 0)
36569b279fSLingrui98  require(numWays >= 1)
37569b279fSLingrui98  require(tagWidth >= 0)
38569b279fSLingrui98  def hasTag       = tagWidth > 0
39569b279fSLingrui98  def multipleWays = numWays > 1
40569b279fSLingrui98  val io = IO(new Bundle {
41569b279fSLingrui98    val wen            = Input(Bool())
42569b279fSLingrui98    val write_idx      = Input(UInt(idxWidth.W))
43569b279fSLingrui98    val write_tag      = if (hasTag) Some(Input(UInt(tagWidth.W))) else None
44569b279fSLingrui98    val write_data     = Input(Vec(numWays, gen))
45569b279fSLingrui98    val write_way_mask = if (multipleWays) Some(Input(Vec(numWays, Bool()))) else None
46569b279fSLingrui98
47478bf92cSYuandongliang    val conflict_valid      = if (extraPort.isDefined) Some(Input(Bool())) else None
48478bf92cSYuandongliang    val conflict_write_data = if (extraPort.isDefined) Some(Input(Vec(numWays, gen))) else None
49478bf92cSYuandongliang    val conflict_way_mask   = if (extraPort.isDefined) Some(Input(UInt(numBr.W))) else None
50478bf92cSYuandongliang
51569b279fSLingrui98    val hit             = Output(Bool())
52569b279fSLingrui98    val hit_data        = Vec(numWays, Valid(gen))
53478bf92cSYuandongliang    val has_conflict    = if (extraPort.isDefined) Some(Output(Bool())) else None
54478bf92cSYuandongliang    val update_idx      = if (extraPort.isDefined) Some(Output(UInt(idxWidth.W))) else None
55478bf92cSYuandongliang    val update_data     = if (extraPort.isDefined) Some(Output(Vec(numWays, gen))) else None
56478bf92cSYuandongliang    val update_way_mask = if (extraPort.isDefined) Some(Output(UInt(numBr.W))) else None
57478bf92cSYuandongliang
58478bf92cSYuandongliang    val conflict_clean = if (extraPort.isDefined) Some(Input(Bool())) else None
59569b279fSLingrui98  })
60569b279fSLingrui98
6176e02f07SLingrui98  class Idx_Tag extends Bundle {
6276e02f07SLingrui98    val idx = UInt(idxWidth.W)
6376e02f07SLingrui98    val tag = if (hasTag) Some(UInt(tagWidth.W)) else None
6476e02f07SLingrui98    def apply(idx: UInt, tag: UInt) = {
6576e02f07SLingrui98      this.idx := idx
6676e02f07SLingrui98      this.tag.map(_ := tag)
6776e02f07SLingrui98    }
6876e02f07SLingrui98  }
69478bf92cSYuandongliang
70478bf92cSYuandongliang  val idx_tag_cam = Module(new IndexableCAMTemplate(new Idx_Tag, numEntries, 1, isIndexable = extraPort.isDefined))
7176e02f07SLingrui98  val data_mem    = Mem(numEntries, Vec(numWays, gen))
72569b279fSLingrui98
73569b279fSLingrui98  val valids       = RegInit(0.U.asTypeOf(Vec(numEntries, Vec(numWays, Bool()))))
7402585c22SLingrui98  val ever_written = RegInit(0.U.asTypeOf(Vec(numEntries, Bool())))
75569b279fSLingrui98
7676e02f07SLingrui98  idx_tag_cam.io.r.req(0)(io.write_idx, io.write_tag.getOrElse(0.U))
7702585c22SLingrui98  val hits_oh = idx_tag_cam.io.r.resp(0).zip(ever_written).map { case (h, ew) => h && ew }
7876e02f07SLingrui98  val hit_idx = OHToUInt(hits_oh)
7976e02f07SLingrui98  val hit     = hits_oh.reduce(_ || _)
80569b279fSLingrui98
81569b279fSLingrui98  io.hit := hit
82569b279fSLingrui98  for (i <- 0 until numWays) {
8376e02f07SLingrui98    io.hit_data(i).valid := Mux1H(hits_oh, valids)(i)
8476e02f07SLingrui98    io.hit_data(i).bits  := data_mem.read(hit_idx)(i)
85569b279fSLingrui98  }
86569b279fSLingrui98
87b3064620SEaston Man  // Replacer
88b3064620SEaston Man  // Because data_mem can only write to one index
89b3064620SEaston Man  // Implementing a per-way replacer is meaningless
90b3064620SEaston Man  // So here use one replacer for all ways
91b3064620SEaston Man  val replacer            = ReplacementPolicy.fromString("plru", numEntries)  // numEntries in total
92b3064620SEaston Man  val replacer_touch_ways = Wire(Vec(1, Valid(UInt(log2Ceil(numEntries).W)))) // One index at a time
93b3064620SEaston Man  val enq_idx             = replacer.way
9476e02f07SLingrui98  val full_mask           = Fill(numWays, 1.U(1.W)).asTypeOf(Vec(numWays, Bool()))
9576e02f07SLingrui98  val update_way_mask     = io.write_way_mask.getOrElse(full_mask)
9676e02f07SLingrui98
9776e02f07SLingrui98  // write data on every request
9876e02f07SLingrui98  when(io.wen) {
9976e02f07SLingrui98    val data_write_idx = Mux(hit, hit_idx, enq_idx)
10076e02f07SLingrui98    data_mem.write(data_write_idx, io.write_data, update_way_mask)
10176e02f07SLingrui98  }
102b3064620SEaston Man  replacer_touch_ways(0).valid := io.wen
103b3064620SEaston Man  replacer_touch_ways(0).bits  := Mux(hit, hit_idx, enq_idx)
104b3064620SEaston Man  replacer.access(replacer_touch_ways)
10576e02f07SLingrui98
10676e02f07SLingrui98  // update valids
107569b279fSLingrui98  for (i <- 0 until numWays) {
108569b279fSLingrui98    when(io.wen) {
109569b279fSLingrui98      when(hit) {
11076e02f07SLingrui98        when(update_way_mask(i)) {
111569b279fSLingrui98          valids(hit_idx)(i) := true.B
112569b279fSLingrui98        }
113569b279fSLingrui98      }.otherwise {
11402585c22SLingrui98        ever_written(enq_idx) := true.B
115569b279fSLingrui98        valids(enq_idx)(i)    := false.B
11676e02f07SLingrui98        when(update_way_mask(i)) {
117569b279fSLingrui98          valids(enq_idx)(i) := true.B
11876e02f07SLingrui98        }
119569b279fSLingrui98      }
120569b279fSLingrui98    }
121569b279fSLingrui98  }
122569b279fSLingrui98
12376e02f07SLingrui98  val enq_en = io.wen && !hit
12476e02f07SLingrui98  idx_tag_cam.io.w.valid      := enq_en
12576e02f07SLingrui98  idx_tag_cam.io.w.bits.index := enq_idx
12676e02f07SLingrui98  idx_tag_cam.io.w.bits.data(io.write_idx, io.write_tag.getOrElse(0.U))
127569b279fSLingrui98
128478bf92cSYuandongliang  // Extra ports are used to handle dual port read/write conflicts
129478bf92cSYuandongliang  if (extraPort.isDefined) {
130478bf92cSYuandongliang    val conflict_flags    = RegInit(0.U.asTypeOf(Vec(numEntries, Bool())))
131478bf92cSYuandongliang    val conflict_way_mask = RegInit(0.U.asTypeOf(io.conflict_way_mask.get))
132478bf92cSYuandongliang    val conflict_data     = RegInit(VecInit(Seq.tabulate(numWays)(i => 0.U.asTypeOf(gen))))
133478bf92cSYuandongliang    val conflict_idx      = OHToUInt(conflict_flags)
134478bf92cSYuandongliang
135478bf92cSYuandongliang    idx_tag_cam.io.ridx.get := conflict_idx
136478bf92cSYuandongliang
137478bf92cSYuandongliang    when(io.wen && io.conflict_valid.getOrElse(false.B)) {
138478bf92cSYuandongliang      conflict_flags(Mux(hit, hit_idx, enq_idx)) := true.B
139478bf92cSYuandongliang      conflict_way_mask                          := io.conflict_way_mask.get
140478bf92cSYuandongliang      conflict_data                              := io.conflict_write_data.get
141478bf92cSYuandongliang    }
142478bf92cSYuandongliang    when(io.conflict_clean.getOrElse(false.B)) {
143478bf92cSYuandongliang      conflict_flags(conflict_idx) := false.B
144478bf92cSYuandongliang    }
145478bf92cSYuandongliang    // for update the cached data
146478bf92cSYuandongliang    io.has_conflict.get    := conflict_flags.reduce(_ || _)
147478bf92cSYuandongliang    io.update_idx.get      := idx_tag_cam.io.rdata.get.idx
148478bf92cSYuandongliang    io.update_way_mask.get := conflict_way_mask
149478bf92cSYuandongliang    io.update_data.foreach(_ := conflict_data)
150478bf92cSYuandongliang  } else None
151478bf92cSYuandongliang
152569b279fSLingrui98  XSPerfAccumulate("wrbypass_hit", io.wen && hit)
153569b279fSLingrui98  XSPerfAccumulate("wrbypass_miss", io.wen && !hit)
154569b279fSLingrui98
155*cf7d6b7aSMuzi  XSDebug(
156*cf7d6b7aSMuzi    io.wen && hit,
157*cf7d6b7aSMuzi    p"wrbypass hit entry #${hit_idx}, idx ${io.write_idx}" +
158*cf7d6b7aSMuzi      p"tag ${io.write_tag.getOrElse(0.U)}data ${io.write_data}\n"
159*cf7d6b7aSMuzi  )
160*cf7d6b7aSMuzi  XSDebug(
161*cf7d6b7aSMuzi    io.wen && !hit,
162*cf7d6b7aSMuzi    p"wrbypass enq entry #${enq_idx}, idx ${io.write_idx}" +
163*cf7d6b7aSMuzi      p"tag ${io.write_tag.getOrElse(0.U)}data ${io.write_data}\n"
164*cf7d6b7aSMuzi  )
165569b279fSLingrui98}
166