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 chipsalliance.rocketchip.config.Parameters 19import chisel3._ 20import chisel3.util._ 21import xiangshan._ 22import utils._ 23import chisel3.experimental.chiselName 24import xiangshan.cache.mmu.CAMTemplate 25 26class WrBypass[T <: Data](gen: T, val numEntries: Int, val idxWidth: Int, 27 val numWays: Int = 1, val tagWidth: Int = 0)(implicit p: Parameters) extends XSModule { 28 require(numEntries >= 0) 29 require(idxWidth > 0) 30 require(numWays >= 1) 31 require(tagWidth >= 0) 32 def hasTag = tagWidth > 0 33 def multipleWays = numWays > 1 34 val io = IO(new Bundle { 35 val wen = Input(Bool()) 36 val write_idx = Input(UInt(idxWidth.W)) 37 val write_tag = if (hasTag) Some(Input(UInt(tagWidth.W))) else None 38 val write_data = Input(Vec(numWays, gen)) 39 val write_way_mask = if (multipleWays) Some(Input(Vec(numWays, Bool()))) else None 40 41 val hit = Output(Bool()) 42 val hit_data = Vec(numWays, Valid(gen)) 43 }) 44 45 class WrBypassPtr extends CircularQueuePtr[WrBypassPtr](numEntries){ 46 override def cloneType = (new WrBypassPtr).asInstanceOf[this.type] 47 } 48 49 class Idx_Tag extends Bundle { 50 val idx = UInt(idxWidth.W) 51 val tag = if (hasTag) Some(UInt(tagWidth.W)) else None 52 def apply(idx: UInt, tag: UInt) = { 53 this.idx := idx 54 this.tag.map(_ := tag) 55 } 56 } 57 val idx_tag_cam = Module(new CAMTemplate(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 62 val enq_ptr = RegInit(0.U.asTypeOf(new WrBypassPtr)) 63 val enq_idx = enq_ptr.value 64 65 idx_tag_cam.io.r.req(0)(io.write_idx, io.write_tag.getOrElse(0.U)) 66 val hits_oh = idx_tag_cam.io.r.resp(0) 67 val hit_idx = OHToUInt(hits_oh) 68 val hit = hits_oh.reduce(_||_) 69 70 io.hit := hit 71 for (i <- 0 until numWays) { 72 io.hit_data(i).valid := Mux1H(hits_oh, valids)(i) 73 io.hit_data(i).bits := data_mem.read(hit_idx)(i) 74 } 75 76 val full_mask = Fill(numWays, 1.U(1.W)).asTypeOf(Vec(numWays, Bool())) 77 val update_way_mask = io.write_way_mask.getOrElse(full_mask) 78 79 // write data on every request 80 when (io.wen) { 81 val data_write_idx = Mux(hit, hit_idx, enq_idx) 82 data_mem.write(data_write_idx, io.write_data, update_way_mask) 83 } 84 85 // update valids 86 for (i <- 0 until numWays) { 87 when (io.wen) { 88 when (hit) { 89 when (update_way_mask(i)) { 90 valids(hit_idx)(i) := true.B 91 } 92 }.otherwise { 93 valids(enq_idx)(i) := false.B 94 when (update_way_mask(i)) { 95 valids(enq_idx)(i) := true.B 96 } 97 } 98 } 99 } 100 101 val enq_en = io.wen && !hit 102 idx_tag_cam.io.w.valid := enq_en 103 idx_tag_cam.io.w.bits.index := enq_idx 104 idx_tag_cam.io.w.bits.data(io.write_idx, io.write_tag.getOrElse(0.U)) 105 enq_ptr := enq_ptr + enq_en 106 107 XSPerfAccumulate("wrbypass_hit", io.wen && hit) 108 XSPerfAccumulate("wrbypass_miss", io.wen && !hit) 109 110 XSDebug(io.wen && hit, p"wrbypass hit entry #${hit_idx}, idx ${io.write_idx}" + 111 p"tag ${io.write_tag.getOrElse(0.U)}data ${io.write_data}\n") 112 XSDebug(io.wen && !hit, p"wrbypass enq entry #${enq_idx}, idx ${io.write_idx}" + 113 p"tag ${io.write_tag.getOrElse(0.U)}data ${io.write_data}\n") 114}