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