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 ***************************************************************************************/ 16 17package xiangshan.mem 18 19import org.chipsalliance.cde.config.Parameters 20import chisel3._ 21import chisel3.util._ 22import utils._ 23import utility._ 24import xiangshan._ 25import xiangshan.backend.rob.RobPtr 26import xiangshan.backend.Bundles._ 27import xiangshan.mem._ 28import xiangshan.backend.fu.FuType 29import freechips.rocketchip.diplomacy.BufferParams 30 31class MBufferBundle(implicit p: Parameters) extends VLSUBundle{ 32 val data = UInt(VLEN.W) 33 val mask = UInt(VLENB.W) 34 val flowNum = UInt(flowIdxBits.W) 35 val exceptionVec = ExceptionVec() 36 val uop = new DynInst 37 // val vdOffset = UInt(vOffsetBits.W) 38 val sourceType = VSFQFeedbackType() 39 val flushState = Bool() 40 41 def allReady(): Bool = (flowNum === 0.U) 42} 43 44abstract class BaseVMergeBuffer(isVStore: Boolean=false)(implicit p: Parameters) extends VLSUModule{ 45 val io = IO(new VMergeBufferIO(isVStore)) 46 47 def EnqConnect(source: MergeBufferReq): MBufferBundle = { 48 val sink = WireInit(0.U.asTypeOf(new MBufferBundle)) 49 sink.data := source.data 50 sink.mask := source.mask 51 sink.flowNum := source.flowNum 52 sink.exceptionVec := 0.U.asTypeOf(ExceptionVec()) 53 sink.uop := source.uop 54 sink.sourceType := 0.U.asTypeOf(VSFQFeedbackType()) 55 sink.flushState := false.B 56 sink 57 // sink.vdOffset := source.vdOffset 58 } 59 def DeqConnect(source: MBufferBundle): MemExuOutput = { 60 val sink = WireInit(0.U.asTypeOf(new MemExuOutput(isVector = true))) 61 sink.data := source.data 62 sink.mask.get := source.mask 63 sink.uop.exceptionVec := source.exceptionVec 64 sink.uop := source.uop 65 sink.debug := 0.U.asTypeOf(new DebugBundle) 66 sink.vdIdxInField.get := 0.U 67 sink.vdIdx.get := 0.U 68 sink 69 } 70 def ToLsqConnect(source: MBufferBundle): FeedbackToLsqIO = { 71 val sink = WireInit(0.U.asTypeOf(new FeedbackToLsqIO)) 72 sink.robidx := source.uop.robIdx 73 sink.uopidx := source.uop.uopIdx 74 sink.feedback(VecFeedbacks.COMMIT) := true.B // TODO: 75 sink.feedback(VecFeedbacks.FLUSH) := false.B 76 sink.feedback(VecFeedbacks.LAST) := true.B 77 sink.vaddr := 0.U // TODO: used when exception 78 sink 79 } 80 // freeliset: store valid entries index. 81 // +---+---+--------------+-----+-----+ 82 // | 0 | 1 | ...... | n-2 | n-1 | 83 // +---+---+--------------+-----+-----+ 84 val freeList: FreeList 85 val uopSize: Int 86 val enqWidth = io.fromSplit.length 87 val deqWidth = io.uopWriteback.length 88 89 val entries = Reg(Vec(uopSize, new MBufferBundle)) 90 val needCancel = WireInit(VecInit(Seq.fill(uopSize)(false.B))) 91 val allocated = RegInit(VecInit(Seq.fill(uopSize)(false.B))) 92 val freeMaskVec = WireInit(VecInit(Seq.fill(uopSize)(false.B))) 93 val uopFinish = RegInit(VecInit(Seq.fill(uopSize)(false.B))) 94 val needRSReplay = RegInit(VecInit(Seq.fill(uopSize)(false.B))) 95 // enq, from splitPipeline 96 // val allowEnqueue = 97 val cancelEnq = io.fromSplit.map(_.req.bits.uop.robIdx.needFlush(io.redirect)) 98 val canEnqueue = io.fromSplit.map(_.req.valid) 99 val needEnqueue = (0 until enqWidth).map{i => 100 canEnqueue(i) && !cancelEnq(i) 101 } 102 103 for ((enq, i) <- io.fromSplit.zipWithIndex){ 104 freeList.io.doAllocate(i) := false.B 105 106 freeList.io.allocateReq(i) := true.B 107 108 val offset = PopCount(needEnqueue.take(i)) 109 val canAccept = freeList.io.canAllocate(offset) 110 val enqIndex = freeList.io.allocateSlot(offset) 111 enq.req.ready := canAccept 112 113 when(needEnqueue(i) && enq.req.ready){ 114 freeList.io.doAllocate(i) := true.B 115 // enqueue 116 allocated(enqIndex) := true.B 117 uopFinish(enqIndex) := false.B 118 needRSReplay(enqIndex) := false.B 119 120 entries(enqIndex) := EnqConnect(enq.req.bits)// initial entry 121 } 122 123 enq.resp.bits.mBIndex := enqIndex 124 enq.resp.bits.fail := false.B 125 enq.resp.valid := canAccept //resp in 1 cycle 126 } 127 128 //redirect 129 for (i <- 0 until uopSize){ 130 needCancel(i) := entries(i).uop.robIdx.needFlush(io.redirect) && allocated(i) 131 when (needCancel(i)) { 132 allocated(i) := false.B 133 freeMaskVec(i) := true.B 134 uopFinish(i) := false.B 135 needRSReplay(i):= false.B 136 } 137 } 138 freeList.io.free := freeMaskVec.asUInt 139 //pipelineWriteback 140 for((pipewb) <- io.fromPipeline){ 141 val wbIndex = pipewb.bits.mBIndex 142 val flowNumNext = Mux(pipewb.bits.usSecondInv, entries(wbIndex).flowNum - 2.U, entries(wbIndex).flowNum - 1.U) 143 val sourceTypeNext = entries(wbIndex).sourceType | pipewb.bits.sourceType 144 val hasExp = pipewb.bits.exceptionVec.asUInt.orR 145 val exceptionVecNext = Mux(hasExp, pipewb.bits.exceptionVec, entries(wbIndex).exceptionVec) 146 when(pipewb.valid){ 147 entries(wbIndex).flowNum := flowNumNext 148 entries(wbIndex).sourceType := sourceTypeNext 149 entries(wbIndex).exceptionVec := exceptionVecNext 150 entries(wbIndex).flushState := pipewb.bits.flushState 151 } 152 when(pipewb.valid && !pipewb.bits.hit){ 153 needRSReplay(wbIndex) := true.B 154 } 155 pipewb.ready := true.B 156 XSError((flowNumNext > entries(wbIndex).flowNum) && pipewb.valid, "FlowWriteback overflow!!\n") 157 XSError(!allocated(wbIndex) && pipewb.valid, "Writeback error flow!!\n") 158 } 159 // for inorder mem asscess 160 io.toSplit := DontCare 161 162 //uopwriteback(deq) 163 for (i <- 0 until uopSize){ 164 when(allocated(i) && entries(i).allReady()){ 165 uopFinish(i) := true.B 166 } 167 } 168 val selPolicy = SelectOne("circ", uopFinish, deqWidth) // select one entry to deq 169 for(((port, lsqport), i) <- (io.uopWriteback zip io.toLsq).zipWithIndex){ 170 val (selValid, selOHVec) = selPolicy.getNthOH(i + 1) 171 val entryIdx = OHToUInt(selOHVec) 172 val selEntry = entries(entryIdx) 173 when(selValid){ 174 freeMaskVec(entryIdx) := true.B 175 allocated(entryIdx) := false.B 176 uopFinish(entryIdx) := false.B 177 needRSReplay(entryIdx):= false.B 178 } 179 //writeback connect 180 port.valid := selValid && allocated(entryIdx) && !needRSReplay(entryIdx) 181 port.bits := DeqConnect(selEntry) 182 //to lsq 183 lsqport.bits := ToLsqConnect(selEntry) // when uopwriteback, free MBuffer entry, write to lsq 184 lsqport.valid:= selValid && allocated(entryIdx) && !needRSReplay(entryIdx) 185 //to RS 186 io.feedback(i).valid := selValid && allocated(entryIdx) && needRSReplay(entryIdx) 187 io.feedback(i).bits.hit := !needRSReplay(entryIdx) 188 io.feedback(i).bits.robIdx := selEntry.uop.robIdx 189 io.feedback(i).bits.sourceType := selEntry.sourceType 190 io.feedback(i).bits.flushState := selEntry.flushState 191 io.feedback(i).bits.dataInvalidSqIdx := DontCare 192 } 193} 194 195class VLMergeBufferImp(implicit p: Parameters) extends BaseVMergeBuffer(isVStore=false){ 196 override lazy val uopSize = VlMergeBufferSize 197 println(s"VLMergeBuffer Size: ${VlMergeBufferSize}") 198 override lazy val freeList = Module(new FreeList( 199 size = uopSize, 200 allocWidth = VecLoadPipelineWidth, 201 freeWidth = deqWidth, 202 enablePreAlloc = false, 203 moduleName = "VLoad MergeBuffer freelist" 204 )) 205 206 //merge data 207 val flowWbElemIdx = Wire(Vec(VecLoadPipelineWidth, UInt(elemIdxBits.W))) 208 val flowWbElemIdxInVd = Wire(Vec(VecLoadPipelineWidth, UInt(elemIdxBits.W))) 209 210 for((pipewb, i) <- io.fromPipeline.zipWithIndex){ 211 val wbIndex = pipewb.bits.mBIndex 212 val alignedType = pipewb.bits.alignedType.get 213 val elemIdxInsideVd = pipewb.bits.elemIdxInsideVd 214 flowWbElemIdx(i) := pipewb.bits.elemIdx.get 215 flowWbElemIdxInVd(i) := elemIdxInsideVd.get 216 // handle the situation where multiple ports are going to write the same uop queue entry 217 val mergedByPrevPort = (i != 0).B && Cat((0 until i).map(j => 218 io.fromPipeline(j).bits.mBIndex === pipewb.bits.mBIndex)).orR 219 val mergePortVec = (0 until VecLoadPipelineWidth).map(j => (j == i).B || 220 (j > i).B && 221 io.fromPipeline(j).bits.mBIndex === pipewb.bits.mBIndex && 222 io.fromPipeline(j).valid) 223 val mergeExpPortVec = (0 until VecLoadPipelineWidth).map(j => mergePortVec(j)) 224 val mergedData = mergeDataWithElemIdx( 225 oldData = entries(wbIndex).data, 226 newData = io.fromPipeline.map(_.bits.vecdata.get), 227 alignedType = alignedType(1,0), 228 elemIdx = flowWbElemIdxInVd, 229 valids = mergeExpPortVec 230 ) 231 val usMergeData = mergeDataByoffset( 232 oldData = entries(wbIndex).data, 233 newData = io.fromPipeline.map(_.bits.vecdata.get), 234 mask = io.fromPipeline.map(_.bits.mask.get), 235 offset = io.fromPipeline.map(_.bits.reg_offset.get), 236 valids = mergeExpPortVec 237 ) 238 when(pipewb.valid && !mergedByPrevPort){ 239 entries(wbIndex).data := Mux(alignedType(2), usMergeData, mergedData) // if aligned(2) == 1, is Unit-Stride inst 240 } 241 } 242} 243 244class VSMergeBufferImp(implicit p: Parameters) extends BaseVMergeBuffer(isVStore=true){ 245 override lazy val uopSize = VsMergeBufferSize 246 println(s"VSMergeBuffer Size: ${VsMergeBufferSize}") 247 override lazy val freeList = Module(new FreeList( 248 size = uopSize, 249 allocWidth = VecStorePipelineWidth, 250 freeWidth = deqWidth, 251 enablePreAlloc = false, 252 moduleName = "VStore MergeBuffer freelist" 253 )) 254 override def DeqConnect(source: MBufferBundle): MemExuOutput = { 255 val sink = Wire(new MemExuOutput(isVector = true)) 256 sink.data := source.data 257 sink.mask.get := source.mask 258 sink.uop.exceptionVec := source.exceptionVec 259 sink.uop := source.uop 260 sink.debug := 0.U.asTypeOf(new DebugBundle) 261 sink.vdIdxInField.get := 0.U 262 sink.vdIdx.get := 0.U 263 sink 264 } 265} 266