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