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