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