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.mem 17 18import chisel3._ 19import chisel3.util._ 20import org.chipsalliance.cde.config._ 21import xiangshan._ 22import xiangshan.backend.rob.RobPtr 23import xiangshan.cache._ 24import utils._ 25import utility._ 26import xiangshan.backend.Bundles.DynInst 27 28class LoadQueueRAR(implicit p: Parameters) extends XSModule 29 with HasDCacheParameters 30 with HasCircularQueuePtrHelper 31 with HasLoadHelper 32 with HasPerfEvents 33{ 34 val io = IO(new Bundle() { 35 // control 36 val redirect = Flipped(Valid(new Redirect)) 37 val vecFeedback = Vec(VecLoadPipelineWidth, Flipped(ValidIO(new FeedbackToLsqIO))) 38 39 // violation query 40 val query = Vec(LoadPipelineWidth, Flipped(new LoadNukeQueryIO)) 41 42 // release cacheline 43 val release = Flipped(Valid(new Release)) 44 45 // from VirtualLoadQueue 46 val ldWbPtr = Input(new LqPtr) 47 48 // global 49 val lqFull = Output(Bool()) 50 }) 51 52 println("LoadQueueRAR: size: " + LoadQueueRARSize) 53 // LoadQueueRAR field 54 // +-------+-------+-------+----------+----+ 55 // | Valid | Uop | PAddr | Released | NC | 56 // +-------+-------+-------+----------+----+ 57 // 58 // Field descriptions: 59 // Allocated : entry is valid. 60 // MicroOp : Micro-op 61 // PAddr : physical address. 62 // Released : DCache released. 63 // NC : is NC with data. 64 val allocated = RegInit(VecInit(List.fill(LoadQueueRARSize)(false.B))) // The control signals need to explicitly indicate the initial value 65 val uop = Reg(Vec(LoadQueueRARSize, new DynInst)) 66 val paddrModule = Module(new LqPAddrModule( 67 gen = UInt(PAddrBits.W), 68 numEntries = LoadQueueRARSize, 69 numRead = LoadPipelineWidth, 70 numWrite = LoadPipelineWidth, 71 numWBank = LoadQueueNWriteBanks, 72 numWDelay = 2, 73 numCamPort = LoadPipelineWidth 74 )) 75 paddrModule.io := DontCare 76 val released = RegInit(VecInit(List.fill(LoadQueueRARSize)(false.B))) 77 val nc = RegInit(VecInit(List.fill(LoadQueueRARSize)(false.B))) 78 val bypassPAddr = Reg(Vec(LoadPipelineWidth, UInt(PAddrBits.W))) 79 80 // freeliset: store valid entries index. 81 // +---+---+--------------+-----+-----+ 82 // | 0 | 1 | ...... | n-2 | n-1 | 83 // +---+---+--------------+-----+-----+ 84 val freeList = Module(new FreeList( 85 size = LoadQueueRARSize, 86 allocWidth = LoadPipelineWidth, 87 freeWidth = 4, 88 enablePreAlloc = true, 89 moduleName = "LoadQueueRAR freelist" 90 )) 91 freeList.io := DontCare 92 93 // Real-allocation: load_s2 94 // PAddr write needs 2 cycles, release signal should delay 1 cycle so that 95 // load enqueue can catch release. 96 val release1Cycle = io.release 97 // val release2Cycle = RegNext(io.release) 98 // val release2Cycle_dup_lsu = RegNext(io.release) 99 val release2Cycle = RegEnable(io.release, io.release.valid) 100 release2Cycle.valid := RegNext(io.release.valid) 101 //val release2Cycle_dup_lsu = RegEnable(io.release, io.release.valid) 102 103 // LoadQueueRAR enqueue condition: 104 // There are still not completed load instructions before the current load instruction. 105 // (e.g. "not completed" means that load instruction get the data or exception). 106 val canEnqueue = io.query.map(_.req.valid) 107 val cancelEnqueue = io.query.map(_.req.bits.uop.robIdx.needFlush(io.redirect)) 108 val hasNotWritebackedLoad = io.query.map(_.req.bits.uop.lqIdx).map(lqIdx => isAfter(lqIdx, io.ldWbPtr)) 109 val needEnqueue = canEnqueue.zip(hasNotWritebackedLoad).zip(cancelEnqueue).map { case ((v, r), c) => v && r && !c } 110 111 // Allocate logic 112 val acceptedVec = Wire(Vec(LoadPipelineWidth, Bool())) 113 val enqIndexVec = Wire(Vec(LoadPipelineWidth, UInt(log2Up(LoadQueueRARSize).W))) 114 115 for ((enq, w) <- io.query.map(_.req).zipWithIndex) { 116 acceptedVec(w) := false.B 117 paddrModule.io.wen(w) := false.B 118 freeList.io.doAllocate(w) := false.B 119 120 freeList.io.allocateReq(w) := true.B 121 122 // Allocate ready 123 val offset = PopCount(needEnqueue.take(w)) 124 val canAccept = freeList.io.canAllocate(offset) 125 val enqIndex = freeList.io.allocateSlot(offset) 126 enq.ready := Mux(needEnqueue(w), canAccept, true.B) 127 128 enqIndexVec(w) := enqIndex 129 when (needEnqueue(w) && enq.ready) { 130 acceptedVec(w) := true.B 131 132 val debug_robIdx = enq.bits.uop.robIdx.asUInt 133 XSError(allocated(enqIndex), p"LoadQueueRAR: You can not write an valid entry! check: ldu $w, robIdx $debug_robIdx") 134 135 freeList.io.doAllocate(w) := true.B 136 // Allocate new entry 137 allocated(enqIndex) := true.B 138 139 // Write paddr 140 paddrModule.io.wen(w) := true.B 141 paddrModule.io.waddr(w) := enqIndex 142 paddrModule.io.wdata(w) := enq.bits.paddr 143 bypassPAddr(w) := enq.bits.paddr 144 145 // Fill info 146 uop(enqIndex) := enq.bits.uop 147 released(enqIndex) := 148 enq.bits.data_valid && 149 (release2Cycle.valid && 150 enq.bits.paddr(PAddrBits-1, DCacheLineOffset) === release2Cycle.bits.paddr(PAddrBits-1, DCacheLineOffset) || 151 release1Cycle.valid && 152 enq.bits.paddr(PAddrBits-1, DCacheLineOffset) === release1Cycle.bits.paddr(PAddrBits-1, DCacheLineOffset)) 153 nc(enqIndex) := enq.bits.is_nc 154 } 155 } 156 157 // LoadQueueRAR deallocate 158 val freeMaskVec = Wire(Vec(LoadQueueRARSize, Bool())) 159 160 // init 161 freeMaskVec.map(e => e := false.B) 162 163 // when the loads that "older than" current load were writebacked, 164 // current load will be released. 165 val vecLdCanceltmp = Wire(Vec(LoadQueueRARSize, Vec(VecLoadPipelineWidth, Bool()))) 166 val vecLdCancel = Wire(Vec(LoadQueueRARSize, Bool())) 167 for (i <- 0 until LoadQueueRARSize) { 168 val deqNotBlock = !isBefore(io.ldWbPtr, uop(i).lqIdx) 169 val needFlush = uop(i).robIdx.needFlush(io.redirect) 170 val fbk = io.vecFeedback 171 for (j <- 0 until VecLoadPipelineWidth) { 172 vecLdCanceltmp(i)(j) := allocated(i) && fbk(j).valid && fbk(j).bits.isFlush && uop(i).robIdx === fbk(j).bits.robidx && uop(i).uopIdx === fbk(j).bits.uopidx 173 } 174 vecLdCancel(i) := vecLdCanceltmp(i).reduce(_ || _) 175 176 when (allocated(i) && (deqNotBlock || needFlush || vecLdCancel(i))) { 177 allocated(i) := false.B 178 freeMaskVec(i) := true.B 179 } 180 } 181 182 // if need replay revoke entry 183 val lastCanAccept = GatedRegNext(acceptedVec) 184 val lastAllocIndex = GatedRegNext(enqIndexVec) 185 186 for ((revoke, w) <- io.query.map(_.revoke).zipWithIndex) { 187 val revokeValid = revoke && lastCanAccept(w) 188 val revokeIndex = lastAllocIndex(w) 189 190 when (allocated(revokeIndex) && revokeValid) { 191 allocated(revokeIndex) := false.B 192 freeMaskVec(revokeIndex) := true.B 193 } 194 } 195 196 freeList.io.free := freeMaskVec.asUInt 197 198 // LoadQueueRAR Query 199 // Load-to-Load violation check condition: 200 // 1. Physical address match by CAM port. 201 // 2. release or nc_with_data is set. 202 // 3. Younger than current load instruction. 203 val ldLdViolation = Wire(Vec(LoadPipelineWidth, Bool())) 204 //val allocatedUInt = RegNext(allocated.asUInt) 205 for ((query, w) <- io.query.zipWithIndex) { 206 ldLdViolation(w) := false.B 207 paddrModule.io.releaseViolationMdata(w) := query.req.bits.paddr 208 209 query.resp.valid := RegNext(query.req.valid) 210 // Generate real violation mask 211 val robIdxMask = VecInit(uop.map(_.robIdx).map(isAfter(_, query.req.bits.uop.robIdx))) 212 val matchMaskReg = Wire(Vec(LoadQueueRARSize, Bool())) 213 for(i <- 0 until LoadQueueRARSize) { 214 matchMaskReg(i) := (allocated(i) & 215 paddrModule.io.releaseViolationMmask(w)(i) & 216 robIdxMask(i) && 217 (nc(i) || released(i))) 218 } 219 val matchMask = GatedValidRegNext(matchMaskReg) 220 // Load-to-Load violation check result 221 val ldLdViolationMask = matchMask 222 ldLdViolationMask.suggestName("ldLdViolationMask_" + w) 223 query.resp.bits.rep_frm_fetch := ParallelORR(ldLdViolationMask) 224 } 225 226 227 // When io.release.valid (release1cycle.valid), it uses the last ld-ld paddr cam port to 228 // update release flag in 1 cycle 229 val releaseVioMask = Reg(Vec(LoadQueueRARSize, Bool())) 230 when (release1Cycle.valid) { 231 paddrModule.io.releaseMdata.takeRight(1)(0) := release1Cycle.bits.paddr 232 } 233 234 val lastAllocIndexOH = lastAllocIndex.map(UIntToOH(_)) 235 val lastReleasePAddrMatch = VecInit((0 until LoadPipelineWidth).map(i => { 236 (bypassPAddr(i)(PAddrBits-1, DCacheLineOffset) === release1Cycle.bits.paddr(PAddrBits-1, DCacheLineOffset)) 237 })) 238 (0 until LoadQueueRARSize).map(i => { 239 val bypassMatch = VecInit((0 until LoadPipelineWidth).map(j => lastCanAccept(j) && lastAllocIndexOH(j)(i) && lastReleasePAddrMatch(j))).asUInt.orR 240 when (RegNext((paddrModule.io.releaseMmask.takeRight(1)(0)(i) || bypassMatch) && allocated(i) && release1Cycle.valid)) { 241 // Note: if a load has missed in dcache and is waiting for refill in load queue, 242 // its released flag still needs to be set as true if addr matches. 243 released(i) := true.B 244 } 245 }) 246 247 io.lqFull := freeList.io.empty 248 249 // perf cnt 250 val canEnqCount = PopCount(io.query.map(_.req.fire)) 251 val validCount = freeList.io.validCount 252 val allowEnqueue = validCount <= (LoadQueueRARSize - LoadPipelineWidth).U 253 val ldLdViolationCount = PopCount(io.query.map(_.resp).map(resp => resp.valid && resp.bits.rep_frm_fetch)) 254 255 QueuePerf(LoadQueueRARSize, validCount, !allowEnqueue) 256 XSPerfAccumulate("enq", canEnqCount) 257 XSPerfAccumulate("ld_ld_violation", ldLdViolationCount) 258 val perfEvents: Seq[(String, UInt)] = Seq( 259 ("enq", canEnqCount), 260 ("ld_ld_violation", ldLdViolationCount) 261 ) 262 generatePerfEvent() 263 // End 264}