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***************************************************************************************/ 16package xiangshan.frontend 17 18import chisel3._ 19import chisel3.util._ 20import org.chipsalliance.cde.config.Parameters 21import utility._ 22import xiangshan._ 23 24class WrBypass[T <: Data]( 25 gen: T, 26 val numEntries: Int, 27 val idxWidth: Int, 28 val numWays: Int = 1, 29 val tagWidth: Int = 0 30)(implicit p: Parameters) extends XSModule { 31 require(numEntries >= 0) 32 require(idxWidth > 0) 33 require(numWays >= 1) 34 require(tagWidth >= 0) 35 def hasTag = tagWidth > 0 36 def multipleWays = numWays > 1 37 val io = IO(new Bundle { 38 val wen = Input(Bool()) 39 val write_idx = Input(UInt(idxWidth.W)) 40 val write_tag = if (hasTag) Some(Input(UInt(tagWidth.W))) else None 41 val write_data = Input(Vec(numWays, gen)) 42 val write_way_mask = if (multipleWays) Some(Input(Vec(numWays, Bool()))) else None 43 44 val hit = Output(Bool()) 45 val hit_data = Vec(numWays, Valid(gen)) 46 }) 47 48 class Idx_Tag extends Bundle { 49 val idx = UInt(idxWidth.W) 50 val tag = if (hasTag) Some(UInt(tagWidth.W)) else None 51 def apply(idx: UInt, tag: UInt) = { 52 this.idx := idx 53 this.tag.map(_ := tag) 54 } 55 } 56 57 val idx_tag_cam = Module(new IndexableCAMTemplate(new Idx_Tag, numEntries, 1)) 58 val data_mem = Mem(numEntries, Vec(numWays, gen)) 59 60 val valids = RegInit(0.U.asTypeOf(Vec(numEntries, Vec(numWays, Bool())))) 61 val ever_written = RegInit(0.U.asTypeOf(Vec(numEntries, Bool()))) 62 63 idx_tag_cam.io.r.req(0)(io.write_idx, io.write_tag.getOrElse(0.U)) 64 val hits_oh = idx_tag_cam.io.r.resp(0).zip(ever_written).map { case (h, ew) => h && ew } 65 val hit_idx = OHToUInt(hits_oh) 66 val hit = hits_oh.reduce(_ || _) 67 68 io.hit := hit 69 for (i <- 0 until numWays) { 70 io.hit_data(i).valid := Mux1H(hits_oh, valids)(i) 71 io.hit_data(i).bits := data_mem.read(hit_idx)(i) 72 } 73 74 // Replacer 75 // Because data_mem can only write to one index 76 // Implementing a per-way replacer is meaningless 77 // So here use one replacer for all ways 78 val replacer = ReplacementPolicy.fromString("plru", numEntries) // numEntries in total 79 val replacer_touch_ways = Wire(Vec(1, Valid(UInt(log2Ceil(numEntries).W)))) // One index at a time 80 val enq_idx = replacer.way 81 val full_mask = Fill(numWays, 1.U(1.W)).asTypeOf(Vec(numWays, Bool())) 82 val update_way_mask = io.write_way_mask.getOrElse(full_mask) 83 84 // write data on every request 85 when(io.wen) { 86 val data_write_idx = Mux(hit, hit_idx, enq_idx) 87 data_mem.write(data_write_idx, io.write_data, update_way_mask) 88 } 89 replacer_touch_ways(0).valid := io.wen 90 replacer_touch_ways(0).bits := Mux(hit, hit_idx, enq_idx) 91 replacer.access(replacer_touch_ways) 92 93 // update valids 94 for (i <- 0 until numWays) { 95 when(io.wen) { 96 when(hit) { 97 when(update_way_mask(i)) { 98 valids(hit_idx)(i) := true.B 99 } 100 }.otherwise { 101 ever_written(enq_idx) := true.B 102 valids(enq_idx)(i) := false.B 103 when(update_way_mask(i)) { 104 valids(enq_idx)(i) := true.B 105 } 106 } 107 } 108 } 109 110 val enq_en = io.wen && !hit 111 idx_tag_cam.io.w.valid := enq_en 112 idx_tag_cam.io.w.bits.index := enq_idx 113 idx_tag_cam.io.w.bits.data(io.write_idx, io.write_tag.getOrElse(0.U)) 114 115 XSPerfAccumulate("wrbypass_hit", io.wen && hit) 116 XSPerfAccumulate("wrbypass_miss", io.wen && !hit) 117 118 XSDebug( 119 io.wen && hit, 120 p"wrbypass hit entry #${hit_idx}, idx ${io.write_idx}" + 121 p"tag ${io.write_tag.getOrElse(0.U)}data ${io.write_data}\n" 122 ) 123 XSDebug( 124 io.wen && !hit, 125 p"wrbypass enq entry #${enq_idx}, idx ${io.write_idx}" + 126 p"tag ${io.write_tag.getOrElse(0.U)}data ${io.write_data}\n" 127 ) 128} 129