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