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