1e9e6cd09SYanqin Li/*************************************************************************************** 2e9e6cd09SYanqin Li * Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC) 3e9e6cd09SYanqin Li * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 4e9e6cd09SYanqin Li * Copyright (c) 2020-2021 Peng Cheng Laboratory 5e9e6cd09SYanqin Li * 6e9e6cd09SYanqin Li * XiangShan is licensed under Mulan PSL v2. 7e9e6cd09SYanqin Li * You can use this software according to the terms and conditions of the Mulan PSL v2. 8e9e6cd09SYanqin Li * You may obtain a copy of Mulan PSL v2 at: 9e9e6cd09SYanqin Li * http://license.coscl.org.cn/MulanPSL2 10e9e6cd09SYanqin Li * 11e9e6cd09SYanqin Li * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 12e9e6cd09SYanqin Li * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 13e9e6cd09SYanqin Li * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 14e9e6cd09SYanqin Li * 15e9e6cd09SYanqin Li * See the Mulan PSL v2 for more details. 16e9e6cd09SYanqin Li ***************************************************************************************/ 17e9e6cd09SYanqin Lipackage xiangshan.mem 18e9e6cd09SYanqin Li 199e12e8edScz4eimport org.chipsalliance.cde.config._ 20e9e6cd09SYanqin Liimport chisel3._ 21e9e6cd09SYanqin Liimport chisel3.util._ 22e9e6cd09SYanqin Liimport utils._ 23e9e6cd09SYanqin Liimport utility._ 249e12e8edScz4eimport xiangshan._ 259e12e8edScz4eimport xiangshan.ExceptionNO._ 269e12e8edScz4eimport xiangshan.backend.rob.{RobPtr, RobLsqIO} 27e9e6cd09SYanqin Liimport xiangshan.backend.Bundles 28e9e6cd09SYanqin Liimport xiangshan.backend.Bundles.{DynInst, MemExuOutput} 29e9e6cd09SYanqin Liimport xiangshan.backend.fu.FuConfig.LduCfg 309e12e8edScz4eimport xiangshan.mem.Bundles._ 319e12e8edScz4eimport xiangshan.cache._ 32e9e6cd09SYanqin Li 33e9e6cd09SYanqin Liclass UncacheEntry(entryIndex: Int)(implicit p: Parameters) extends XSModule 34e9e6cd09SYanqin Li with HasCircularQueuePtrHelper 35e9e6cd09SYanqin Li with HasLoadHelper 36e9e6cd09SYanqin Li{ 37e9e6cd09SYanqin Li val io = IO(new Bundle() { 38e9e6cd09SYanqin Li /* control */ 39e9e6cd09SYanqin Li val redirect = Flipped(Valid(new Redirect)) 40e9e6cd09SYanqin Li // redirect flush 41e9e6cd09SYanqin Li val flush = Output(Bool()) 42e9e6cd09SYanqin Li // mmio commit 43e9e6cd09SYanqin Li val rob = Flipped(new RobLsqIO) 44e9e6cd09SYanqin Li // mmio select 45e9e6cd09SYanqin Li val mmioSelect = Output(Bool()) 4674050fc0SYanqin Li // slaveId 4774050fc0SYanqin Li val slaveId = ValidIO(UInt(UncacheBufferIndexWidth.W)) 48e9e6cd09SYanqin Li 49e9e6cd09SYanqin Li /* transaction */ 50e9e6cd09SYanqin Li // from ldu 51e9e6cd09SYanqin Li val req = Flipped(Valid(new LqWriteBundle)) 52e9e6cd09SYanqin Li // to ldu: mmio, data 53e9e6cd09SYanqin Li val mmioOut = DecoupledIO(new MemExuOutput) 54e9e6cd09SYanqin Li val mmioRawData = Output(new LoadDataFromLQBundle) 55e9e6cd09SYanqin Li // to ldu: nc with data 56e9e6cd09SYanqin Li val ncOut = DecoupledIO(new LsPipelineBundle) 57e9e6cd09SYanqin Li // <=> uncache 58e9e6cd09SYanqin Li val uncache = new UncacheWordIO 59e9e6cd09SYanqin Li // exception generated by outer bus 60e9e6cd09SYanqin Li val exception = Valid(new LqWriteBundle) 61e9e6cd09SYanqin Li }) 62e9e6cd09SYanqin Li 63e9e6cd09SYanqin Li val req_valid = RegInit(false.B) 64e9e6cd09SYanqin Li val req = Reg(new LqWriteBundle) 6574050fc0SYanqin Li val slaveAccept = RegInit(false.B) 6674050fc0SYanqin Li val slaveId = Reg(UInt(UncacheBufferIndexWidth.W)) 67e9e6cd09SYanqin Li 68e9e6cd09SYanqin Li val s_idle :: s_req :: s_resp :: s_wait :: Nil = Enum(4) 69e9e6cd09SYanqin Li val uncacheState = RegInit(s_idle) 70e9e6cd09SYanqin Li val uncacheData = Reg(io.uncache.resp.bits.data.cloneType) 71e9e6cd09SYanqin Li val nderr = RegInit(false.B) 72e9e6cd09SYanqin Li 73e9e6cd09SYanqin Li val writeback = Mux(req.nc, io.ncOut.fire, io.mmioOut.fire) 7474050fc0SYanqin Li val slaveAck = req_valid && io.uncache.idResp.valid && io.uncache.idResp.bits.mid === entryIndex.U 75e9e6cd09SYanqin Li 76e9e6cd09SYanqin Li /** 77e9e6cd09SYanqin Li * Flush 78e9e6cd09SYanqin Li * 79e9e6cd09SYanqin Li * 1. direct flush during idle 80e9e6cd09SYanqin Li * 2. otherwise delayed flush until receiving uncache resp 81e9e6cd09SYanqin Li */ 82e9e6cd09SYanqin Li val needFlushReg = RegInit(false.B) 83e9e6cd09SYanqin Li val needFlush = req_valid && req.uop.robIdx.needFlush(io.redirect) 84*afa1262cSYanqin Li val flush = WireInit(false.B) 85e9e6cd09SYanqin Li when(flush){ 86e9e6cd09SYanqin Li needFlushReg := false.B 87e9e6cd09SYanqin Li }.elsewhen(needFlush){ 88e9e6cd09SYanqin Li needFlushReg := true.B 89e9e6cd09SYanqin Li } 90e9e6cd09SYanqin Li 91e9e6cd09SYanqin Li /* enter req */ 92e9e6cd09SYanqin Li when (flush) { 93e9e6cd09SYanqin Li req_valid := false.B 9474050fc0SYanqin Li slaveAccept := false.B 95e9e6cd09SYanqin Li } .elsewhen (io.req.valid) { 96e9e6cd09SYanqin Li req_valid := true.B 9774050fc0SYanqin Li slaveAccept := false.B 98e9e6cd09SYanqin Li req := io.req.bits 99e9e6cd09SYanqin Li nderr := false.B 10074050fc0SYanqin Li } .elsewhen(slaveAck) { 10174050fc0SYanqin Li slaveAccept := true.B 10274050fc0SYanqin Li slaveId := io.uncache.idResp.bits.sid 103e9e6cd09SYanqin Li } .elsewhen (writeback) { 104e9e6cd09SYanqin Li req_valid := false.B 10574050fc0SYanqin Li slaveAccept := false.B 106e9e6cd09SYanqin Li } 1078b33cd30Sklin02 XSError(!flush && io.req.valid && req_valid, p"LoadQueueUncache: You can not write an valid entry: $entryIndex") 108e9e6cd09SYanqin Li 109e9e6cd09SYanqin Li /** 110e9e6cd09SYanqin Li * Memory mapped IO / NC operations 111e9e6cd09SYanqin Li * 112e9e6cd09SYanqin Li * States: 113e9e6cd09SYanqin Li * (1) s_idle: wait for mmio reaching ROB's head / nc req valid from loadunit 114e9e6cd09SYanqin Li * (2) s_req: wait to be sent to uncache channel until req selected and uncache ready 115e9e6cd09SYanqin Li * (3) s_resp: wait for response from uncache channel 116e9e6cd09SYanqin Li * (4) s_wait: wait for loadunit to receive writeback req 117e9e6cd09SYanqin Li */ 118e9e6cd09SYanqin Li val pendingld = GatedValidRegNext(io.rob.pendingMMIOld) 119e9e6cd09SYanqin Li val pendingPtr = GatedRegNext(io.rob.pendingPtr) 120e9e6cd09SYanqin Li val canSendReq = req_valid && !needFlush && Mux( 121e9e6cd09SYanqin Li req.nc, true.B, 122e9e6cd09SYanqin Li pendingld && req.uop.robIdx === pendingPtr 123e9e6cd09SYanqin Li ) 124e9e6cd09SYanqin Li switch (uncacheState) { 125e9e6cd09SYanqin Li is (s_idle) { 126*afa1262cSYanqin Li when (needFlush) { 127*afa1262cSYanqin Li uncacheState := s_idle 128*afa1262cSYanqin Li flush := true.B 129*afa1262cSYanqin Li }.elsewhen (canSendReq) { 130e9e6cd09SYanqin Li uncacheState := s_req 131e9e6cd09SYanqin Li } 132e9e6cd09SYanqin Li } 133e9e6cd09SYanqin Li is (s_req) { 134*afa1262cSYanqin Li when(needFlush){ 135*afa1262cSYanqin Li uncacheState := s_idle 136*afa1262cSYanqin Li flush := true.B 137*afa1262cSYanqin Li }.elsewhen(io.uncache.req.fire) { 138e9e6cd09SYanqin Li uncacheState := s_resp 139e9e6cd09SYanqin Li } 140e9e6cd09SYanqin Li } 141e9e6cd09SYanqin Li is (s_resp) { 142e9e6cd09SYanqin Li when (io.uncache.resp.fire) { 143*afa1262cSYanqin Li when (needFlush || needFlushReg) { 144e9e6cd09SYanqin Li uncacheState := s_idle 145*afa1262cSYanqin Li flush := true.B 146e9e6cd09SYanqin Li }.otherwise{ 147e9e6cd09SYanqin Li uncacheState := s_wait 148e9e6cd09SYanqin Li } 149e9e6cd09SYanqin Li } 150e9e6cd09SYanqin Li } 151e9e6cd09SYanqin Li is (s_wait) { 152*afa1262cSYanqin Li when (needFlush || writeback) { 153e9e6cd09SYanqin Li uncacheState := s_idle 154*afa1262cSYanqin Li flush := true.B 155e9e6cd09SYanqin Li } 156e9e6cd09SYanqin Li } 157e9e6cd09SYanqin Li } 158e9e6cd09SYanqin Li 159e9e6cd09SYanqin Li /* control */ 160e9e6cd09SYanqin Li io.flush := flush 161e9e6cd09SYanqin Li io.rob.mmio := DontCare 162e9e6cd09SYanqin Li io.rob.uop := DontCare 163e9e6cd09SYanqin Li io.mmioSelect := (uncacheState =/= s_idle) && req.mmio 16474050fc0SYanqin Li io.slaveId.valid := slaveAccept 16574050fc0SYanqin Li io.slaveId.bits := slaveId 166e9e6cd09SYanqin Li 167e9e6cd09SYanqin Li /* uncahce req */ 168*afa1262cSYanqin Li io.uncache.req.valid := uncacheState === s_req && !needFlush 169e9e6cd09SYanqin Li io.uncache.req.bits := DontCare 170e9e6cd09SYanqin Li io.uncache.req.bits.cmd := MemoryOpConstants.M_XRD 171e9e6cd09SYanqin Li io.uncache.req.bits.data := DontCare 172e9e6cd09SYanqin Li io.uncache.req.bits.addr := req.paddr 173e9e6cd09SYanqin Li io.uncache.req.bits.vaddr:= req.vaddr 174e9e6cd09SYanqin Li io.uncache.req.bits.mask := Mux(req.paddr(3), req.mask(15, 8), req.mask(7, 0)) 175e9e6cd09SYanqin Li io.uncache.req.bits.id := entryIndex.U 176e9e6cd09SYanqin Li io.uncache.req.bits.instrtype := DontCare 177e9e6cd09SYanqin Li io.uncache.req.bits.replayCarry := DontCare 178e9e6cd09SYanqin Li io.uncache.req.bits.atomic := req.atomic 179e9e6cd09SYanqin Li io.uncache.req.bits.nc := req.nc 180519244c7SYanqin Li io.uncache.req.bits.memBackTypeMM := req.memBackTypeMM 181e9e6cd09SYanqin Li 182e9e6cd09SYanqin Li io.uncache.resp.ready := true.B 183e9e6cd09SYanqin Li 184e9e6cd09SYanqin Li /* uncahce resp */ 185e9e6cd09SYanqin Li when (io.uncache.resp.fire) { 186e9e6cd09SYanqin Li uncacheData := io.uncache.resp.bits.data 187e9e6cd09SYanqin Li nderr := io.uncache.resp.bits.nderr 188e9e6cd09SYanqin Li } 189e9e6cd09SYanqin Li 190e9e6cd09SYanqin Li /* uncahce writeback */ 191e9e6cd09SYanqin Li val selUop = req.uop 192e9e6cd09SYanqin Li val func = selUop.fuOpType 193e9e6cd09SYanqin Li val raddr = req.paddr 194e9e6cd09SYanqin Li val rdataSel = LookupTree(raddr(2, 0), List( 195e9e6cd09SYanqin Li "b000".U -> uncacheData(63, 0), 196e9e6cd09SYanqin Li "b001".U -> uncacheData(63, 8), 197e9e6cd09SYanqin Li "b010".U -> uncacheData(63, 16), 198e9e6cd09SYanqin Li "b011".U -> uncacheData(63, 24), 199e9e6cd09SYanqin Li "b100".U -> uncacheData(63, 32), 200e9e6cd09SYanqin Li "b101".U -> uncacheData(63, 40), 201e9e6cd09SYanqin Li "b110".U -> uncacheData(63, 48), 202e9e6cd09SYanqin Li "b111".U -> uncacheData(63, 56) 203e9e6cd09SYanqin Li )) 204e9e6cd09SYanqin Li val rdataPartialLoad = rdataHelper(selUop, rdataSel) 205e9e6cd09SYanqin Li 206e9e6cd09SYanqin Li io.mmioOut.valid := false.B 207e9e6cd09SYanqin Li io.mmioOut.bits := DontCare 208e9e6cd09SYanqin Li io.mmioRawData := DontCare 209e9e6cd09SYanqin Li io.ncOut.valid := false.B 210e9e6cd09SYanqin Li io.ncOut.bits := DontCare 211e9e6cd09SYanqin Li 212e9e6cd09SYanqin Li when(req.nc){ 213*afa1262cSYanqin Li io.ncOut.valid := (uncacheState === s_wait) && !needFlush 214e9e6cd09SYanqin Li io.ncOut.bits := DontCare 215e9e6cd09SYanqin Li io.ncOut.bits.uop := selUop 216e9e6cd09SYanqin Li io.ncOut.bits.uop.lqIdx := req.uop.lqIdx 217e9e6cd09SYanqin Li io.ncOut.bits.uop.exceptionVec(loadAccessFault) := nderr 218e9e6cd09SYanqin Li io.ncOut.bits.data := rdataPartialLoad 219e9e6cd09SYanqin Li io.ncOut.bits.paddr := req.paddr 220e9e6cd09SYanqin Li io.ncOut.bits.vaddr := req.vaddr 221e9e6cd09SYanqin Li io.ncOut.bits.nc := true.B 222e9e6cd09SYanqin Li io.ncOut.bits.mask := Mux(req.paddr(3), req.mask(15, 8), req.mask(7, 0)) 223e9e6cd09SYanqin Li io.ncOut.bits.schedIndex := req.schedIndex 224e9e6cd09SYanqin Li io.ncOut.bits.isvec := req.isvec 225e9e6cd09SYanqin Li io.ncOut.bits.is128bit := req.is128bit 226e9e6cd09SYanqin Li io.ncOut.bits.vecActive := req.vecActive 227e9e6cd09SYanqin Li }.otherwise{ 228*afa1262cSYanqin Li io.mmioOut.valid := (uncacheState === s_wait) && !needFlush 229e9e6cd09SYanqin Li io.mmioOut.bits := DontCare 230e9e6cd09SYanqin Li io.mmioOut.bits.uop := selUop 231e9e6cd09SYanqin Li io.mmioOut.bits.uop.lqIdx := req.uop.lqIdx 232e9e6cd09SYanqin Li io.mmioOut.bits.uop.exceptionVec(loadAccessFault) := nderr 233e9e6cd09SYanqin Li io.mmioOut.bits.data := rdataPartialLoad 234e9e6cd09SYanqin Li io.mmioOut.bits.debug.isMMIO := true.B 235e9e6cd09SYanqin Li io.mmioOut.bits.debug.isNC := false.B 236e9e6cd09SYanqin Li io.mmioOut.bits.debug.paddr := req.paddr 237e9e6cd09SYanqin Li io.mmioOut.bits.debug.vaddr := req.vaddr 238e9e6cd09SYanqin Li io.mmioRawData.lqData := uncacheData 239e9e6cd09SYanqin Li io.mmioRawData.uop := req.uop 240e9e6cd09SYanqin Li io.mmioRawData.addrOffset := req.paddr 241e9e6cd09SYanqin Li } 242e9e6cd09SYanqin Li 243e9e6cd09SYanqin Li io.exception.valid := writeback 244e9e6cd09SYanqin Li io.exception.bits := req 245e9e6cd09SYanqin Li io.exception.bits.uop.exceptionVec(loadAccessFault) := nderr 246e9e6cd09SYanqin Li 247e9e6cd09SYanqin Li /* debug log */ 2488b33cd30Sklin02 XSDebug(io.uncache.req.fire, 2498b33cd30Sklin02 "uncache req: pc %x addr %x data %x op %x mask %x\n", 250e9e6cd09SYanqin Li req.uop.pc, 251e9e6cd09SYanqin Li io.uncache.req.bits.addr, 252e9e6cd09SYanqin Li io.uncache.req.bits.data, 253e9e6cd09SYanqin Li io.uncache.req.bits.cmd, 254e9e6cd09SYanqin Li io.uncache.req.bits.mask 255e9e6cd09SYanqin Li ) 2568b33cd30Sklin02 XSInfo(io.ncOut.fire, 2578b33cd30Sklin02 "int load miss write to cbd robidx %d lqidx %d pc 0x%x mmio %x\n", 258e9e6cd09SYanqin Li io.ncOut.bits.uop.robIdx.asUInt, 259e9e6cd09SYanqin Li io.ncOut.bits.uop.lqIdx.asUInt, 260e9e6cd09SYanqin Li io.ncOut.bits.uop.pc, 261e9e6cd09SYanqin Li true.B 262e9e6cd09SYanqin Li ) 2638b33cd30Sklin02 XSInfo(io.mmioOut.fire, 2648b33cd30Sklin02 "int load miss write to cbd robidx %d lqidx %d pc 0x%x mmio %x\n", 265e9e6cd09SYanqin Li io.mmioOut.bits.uop.robIdx.asUInt, 266e9e6cd09SYanqin Li io.mmioOut.bits.uop.lqIdx.asUInt, 267e9e6cd09SYanqin Li io.mmioOut.bits.uop.pc, 268e9e6cd09SYanqin Li true.B 269e9e6cd09SYanqin Li ) 270e9e6cd09SYanqin Li 271e9e6cd09SYanqin Li} 272e9e6cd09SYanqin Li 273e9e6cd09SYanqin Liclass LoadQueueUncache(implicit p: Parameters) extends XSModule 274e9e6cd09SYanqin Li with HasCircularQueuePtrHelper 275e9e6cd09SYanqin Li with HasMemBlockParameters 276e9e6cd09SYanqin Li{ 277e9e6cd09SYanqin Li val io = IO(new Bundle() { 278e9e6cd09SYanqin Li /* control */ 279e9e6cd09SYanqin Li val redirect = Flipped(Valid(new Redirect)) 280e9e6cd09SYanqin Li // mmio commit 281e9e6cd09SYanqin Li val rob = Flipped(new RobLsqIO) 282e9e6cd09SYanqin Li 283e9e6cd09SYanqin Li /* transaction */ 284e9e6cd09SYanqin Li // enqueue: from ldu s3 285e9e6cd09SYanqin Li val req = Vec(LoadPipelineWidth, Flipped(Decoupled(new LqWriteBundle))) 286e9e6cd09SYanqin Li // writeback: mmio to ldu s0, s3 287e9e6cd09SYanqin Li val mmioOut = Vec(LoadPipelineWidth, DecoupledIO(new MemExuOutput)) 288e9e6cd09SYanqin Li val mmioRawData = Vec(LoadPipelineWidth, Output(new LoadDataFromLQBundle)) 289e9e6cd09SYanqin Li // writeback: nc to ldu s0--s3 290e9e6cd09SYanqin Li val ncOut = Vec(LoadPipelineWidth, Decoupled(new LsPipelineBundle)) 291e9e6cd09SYanqin Li // <=>uncache 292e9e6cd09SYanqin Li val uncache = new UncacheWordIO 293e9e6cd09SYanqin Li 294e9e6cd09SYanqin Li /* except */ 295e9e6cd09SYanqin Li // rollback from frontend when buffer is full 296e9e6cd09SYanqin Li val rollback = Output(Valid(new Redirect)) 297e9e6cd09SYanqin Li // exception generated by outer bus 298e9e6cd09SYanqin Li val exception = Valid(new LqWriteBundle) 299e9e6cd09SYanqin Li }) 300e9e6cd09SYanqin Li 301e9e6cd09SYanqin Li /****************************************************************** 302e9e6cd09SYanqin Li * Structure 303e9e6cd09SYanqin Li ******************************************************************/ 304e9e6cd09SYanqin Li val entries = Seq.tabulate(LoadUncacheBufferSize)(i => Module(new UncacheEntry(i))) 305e9e6cd09SYanqin Li 306e9e6cd09SYanqin Li val freeList = Module(new FreeList( 307e9e6cd09SYanqin Li size = LoadUncacheBufferSize, 308e9e6cd09SYanqin Li allocWidth = LoadPipelineWidth, 309e9e6cd09SYanqin Li freeWidth = 4, 310e9e6cd09SYanqin Li enablePreAlloc = true, 311e9e6cd09SYanqin Li moduleName = "LoadQueueUncache freelist" 312e9e6cd09SYanqin Li )) 313e9e6cd09SYanqin Li freeList.io := DontCare 314e9e6cd09SYanqin Li 315e9e6cd09SYanqin Li // set default IO 316e9e6cd09SYanqin Li entries.foreach { 317e9e6cd09SYanqin Li case (e) => 318e9e6cd09SYanqin Li e.io.req.valid := false.B 319e9e6cd09SYanqin Li e.io.req.bits := DontCare 320e9e6cd09SYanqin Li e.io.uncache.req.ready := false.B 32174050fc0SYanqin Li e.io.uncache.idResp.valid := false.B 32274050fc0SYanqin Li e.io.uncache.idResp.bits := DontCare 323e9e6cd09SYanqin Li e.io.uncache.resp.valid := false.B 324e9e6cd09SYanqin Li e.io.uncache.resp.bits := DontCare 325e9e6cd09SYanqin Li e.io.ncOut.ready := false.B 326e9e6cd09SYanqin Li e.io.mmioOut.ready := false.B 327e9e6cd09SYanqin Li } 328e9e6cd09SYanqin Li io.uncache.req.valid := false.B 329e9e6cd09SYanqin Li io.uncache.req.bits := DontCare 330e9e6cd09SYanqin Li io.uncache.resp.ready := false.B 331e9e6cd09SYanqin Li for (w <- 0 until LoadPipelineWidth) { 332e9e6cd09SYanqin Li io.mmioOut(w).valid := false.B 333e9e6cd09SYanqin Li io.mmioOut(w).bits := DontCare 334e9e6cd09SYanqin Li io.mmioRawData(w) := DontCare 335e9e6cd09SYanqin Li io.ncOut(w).valid := false.B 336e9e6cd09SYanqin Li io.ncOut(w).bits := DontCare 337e9e6cd09SYanqin Li } 338e9e6cd09SYanqin Li 339e9e6cd09SYanqin Li 340e9e6cd09SYanqin Li /****************************************************************** 341e9e6cd09SYanqin Li * Enqueue 342e9e6cd09SYanqin Li * 343e9e6cd09SYanqin Li * s1: hold 344e9e6cd09SYanqin Li * s2: confirm enqueue and write entry 345e9e6cd09SYanqin Li * valid: no redirect, no exception, no replay, is mmio/nc 346e9e6cd09SYanqin Li * ready: freelist can allocate 347e9e6cd09SYanqin Li ******************************************************************/ 348e9e6cd09SYanqin Li 349a035c20dSYanqin Li val s1_sortedVec = HwSort(VecInit(io.req.map { case x => DataWithPtr(x.valid, x.bits, x.bits.uop.robIdx) })) 350a035c20dSYanqin Li val s1_req = VecInit(s1_sortedVec.map(_.bits)) 351a035c20dSYanqin Li val s1_valid = VecInit(s1_sortedVec.map(_.valid)) 352e9e6cd09SYanqin Li val s2_enqueue = Wire(Vec(LoadPipelineWidth, Bool())) 353e9e6cd09SYanqin Li io.req.zipWithIndex.foreach{ case (r, i) => 354a035c20dSYanqin Li r.ready := true.B 355e9e6cd09SYanqin Li } 356e9e6cd09SYanqin Li 357e9e6cd09SYanqin Li // s2: enqueue 358e9e6cd09SYanqin Li val s2_req = (0 until LoadPipelineWidth).map(i => {RegEnable(s1_req(i), s1_valid(i))}) 359e9e6cd09SYanqin Li val s2_valid = (0 until LoadPipelineWidth).map(i => { 360e9e6cd09SYanqin Li RegNext(s1_valid(i)) && 361e9e6cd09SYanqin Li !s2_req(i).uop.robIdx.needFlush(RegNext(io.redirect)) && 362e9e6cd09SYanqin Li !s2_req(i).uop.robIdx.needFlush(io.redirect) 363e9e6cd09SYanqin Li }) 364e9e6cd09SYanqin Li val s2_has_exception = s2_req.map(x => ExceptionNO.selectByFu(x.uop.exceptionVec, LduCfg).asUInt.orR) 365e9e6cd09SYanqin Li val s2_need_replay = s2_req.map(_.rep_info.need_rep) 366e9e6cd09SYanqin Li 367e9e6cd09SYanqin Li for (w <- 0 until LoadPipelineWidth) { 368e9e6cd09SYanqin Li s2_enqueue(w) := s2_valid(w) && !s2_has_exception(w) && !s2_need_replay(w) && (s2_req(w).mmio || s2_req(w).nc) 369e9e6cd09SYanqin Li } 370e9e6cd09SYanqin Li 371e9e6cd09SYanqin Li val s2_enqValidVec = Wire(Vec(LoadPipelineWidth, Bool())) 372e9e6cd09SYanqin Li val s2_enqIndexVec = Wire(Vec(LoadPipelineWidth, UInt())) 373e9e6cd09SYanqin Li 374e9e6cd09SYanqin Li for (w <- 0 until LoadPipelineWidth) { 375e9e6cd09SYanqin Li freeList.io.allocateReq(w) := true.B 376e9e6cd09SYanqin Li } 377e9e6cd09SYanqin Li 378e9e6cd09SYanqin Li // freeList real-allocate 379e9e6cd09SYanqin Li for (w <- 0 until LoadPipelineWidth) { 380e9e6cd09SYanqin Li freeList.io.doAllocate(w) := s2_enqValidVec(w) 381e9e6cd09SYanqin Li } 382e9e6cd09SYanqin Li 383e9e6cd09SYanqin Li for (w <- 0 until LoadPipelineWidth) { 384e9e6cd09SYanqin Li val offset = PopCount(s2_enqueue.take(w)) 38554b55f34SYanqin Li s2_enqValidVec(w) := s2_enqueue(w) && freeList.io.canAllocate(offset) 386e9e6cd09SYanqin Li s2_enqIndexVec(w) := freeList.io.allocateSlot(offset) 387e9e6cd09SYanqin Li } 388e9e6cd09SYanqin Li 389e9e6cd09SYanqin Li 390e9e6cd09SYanqin Li /****************************************************************** 391e9e6cd09SYanqin Li * Uncache Transaction 392e9e6cd09SYanqin Li * 393e9e6cd09SYanqin Li * 1. uncache req 394e9e6cd09SYanqin Li * 2. uncache resp 395e9e6cd09SYanqin Li * 3. writeback 396e9e6cd09SYanqin Li ******************************************************************/ 397e9e6cd09SYanqin Li private val NC_WB_MOD = NCWBPorts.length 398e9e6cd09SYanqin Li 399e9e6cd09SYanqin Li val uncacheReq = Wire(DecoupledIO(io.uncache.req.bits.cloneType)) 400e9e6cd09SYanqin Li val mmioSelect = entries.map(e => e.io.mmioSelect).reduce(_ || _) 401e9e6cd09SYanqin Li val mmioReq = Wire(DecoupledIO(io.uncache.req.bits.cloneType)) 402e9e6cd09SYanqin Li // TODO lyq: It's best to choose in robIdx order / the order in which they enter 403e9e6cd09SYanqin Li val ncReqArb = Module(new RRArbiterInit(io.uncache.req.bits.cloneType, LoadUncacheBufferSize)) 404e9e6cd09SYanqin Li 405e9e6cd09SYanqin Li val mmioOut = Wire(DecoupledIO(io.mmioOut(0).bits.cloneType)) 406e9e6cd09SYanqin Li val mmioRawData = Wire(io.mmioRawData(0).cloneType) 407e9e6cd09SYanqin Li val ncOut = Wire(chiselTypeOf(io.ncOut)) 408e9e6cd09SYanqin Li val ncOutValidVec = VecInit(entries.map(e => e.io.ncOut.valid)) 409e9e6cd09SYanqin Li val ncOutValidVecRem = SubVec.getMaskRem(ncOutValidVec, NC_WB_MOD) 410e9e6cd09SYanqin Li 411e9e6cd09SYanqin Li // init 412e9e6cd09SYanqin Li uncacheReq.valid := false.B 413e9e6cd09SYanqin Li uncacheReq.bits := DontCare 414e9e6cd09SYanqin Li mmioReq.valid := false.B 415e9e6cd09SYanqin Li mmioReq.bits := DontCare 416e9e6cd09SYanqin Li mmioOut.valid := false.B 417e9e6cd09SYanqin Li mmioOut.bits := DontCare 418e9e6cd09SYanqin Li mmioRawData := DontCare 419e9e6cd09SYanqin Li for (i <- 0 until LoadUncacheBufferSize) { 420e9e6cd09SYanqin Li ncReqArb.io.in(i).valid := false.B 421e9e6cd09SYanqin Li ncReqArb.io.in(i).bits := DontCare 422e9e6cd09SYanqin Li } 423e9e6cd09SYanqin Li for (i <- 0 until LoadPipelineWidth) { 424e9e6cd09SYanqin Li ncOut(i).valid := false.B 425e9e6cd09SYanqin Li ncOut(i).bits := DontCare 426e9e6cd09SYanqin Li } 427e9e6cd09SYanqin Li 428e9e6cd09SYanqin Li entries.zipWithIndex.foreach { 429e9e6cd09SYanqin Li case (e, i) => 430e9e6cd09SYanqin Li // enqueue 431e9e6cd09SYanqin Li for (w <- 0 until LoadPipelineWidth) { 432e9e6cd09SYanqin Li when (s2_enqValidVec(w) && (i.U === s2_enqIndexVec(w))) { 433e9e6cd09SYanqin Li e.io.req.valid := true.B 434e9e6cd09SYanqin Li e.io.req.bits := s2_req(w) 435e9e6cd09SYanqin Li } 436e9e6cd09SYanqin Li } 437e9e6cd09SYanqin Li 438e9e6cd09SYanqin Li // control 439e9e6cd09SYanqin Li e.io.redirect <> io.redirect 440e9e6cd09SYanqin Li e.io.rob <> io.rob 441e9e6cd09SYanqin Li 442e9e6cd09SYanqin Li // uncache req, writeback 443e9e6cd09SYanqin Li when (e.io.mmioSelect) { 444e9e6cd09SYanqin Li mmioReq.valid := e.io.uncache.req.valid 445e9e6cd09SYanqin Li mmioReq.bits := e.io.uncache.req.bits 446e9e6cd09SYanqin Li e.io.uncache.req.ready := mmioReq.ready 447e9e6cd09SYanqin Li 448e9e6cd09SYanqin Li e.io.mmioOut.ready := mmioOut.ready 449e9e6cd09SYanqin Li mmioOut.valid := e.io.mmioOut.valid 450e9e6cd09SYanqin Li mmioOut.bits := e.io.mmioOut.bits 451e9e6cd09SYanqin Li mmioRawData := e.io.mmioRawData 452e9e6cd09SYanqin Li 453e9e6cd09SYanqin Li }.otherwise{ 454e9e6cd09SYanqin Li ncReqArb.io.in(i).valid := e.io.uncache.req.valid 455e9e6cd09SYanqin Li ncReqArb.io.in(i).bits := e.io.uncache.req.bits 456e9e6cd09SYanqin Li e.io.uncache.req.ready := ncReqArb.io.in(i).ready 457e9e6cd09SYanqin Li 458e9e6cd09SYanqin Li (0 until NC_WB_MOD).map { w => 459e9e6cd09SYanqin Li val (idx, ncOutValid) = PriorityEncoderWithFlag(ncOutValidVecRem(w)) 460e9e6cd09SYanqin Li val port = NCWBPorts(w) 461e9e6cd09SYanqin Li when((i.U === idx) && ncOutValid) { 462e9e6cd09SYanqin Li ncOut(port).valid := ncOutValid 463e9e6cd09SYanqin Li ncOut(port).bits := e.io.ncOut.bits 464e9e6cd09SYanqin Li e.io.ncOut.ready := ncOut(port).ready 465e9e6cd09SYanqin Li } 466e9e6cd09SYanqin Li } 467e9e6cd09SYanqin Li 468e9e6cd09SYanqin Li } 469e9e6cd09SYanqin Li 47074050fc0SYanqin Li // uncache idResp 47174050fc0SYanqin Li when(i.U === io.uncache.idResp.bits.mid) { 47274050fc0SYanqin Li e.io.uncache.idResp <> io.uncache.idResp 47374050fc0SYanqin Li } 47474050fc0SYanqin Li 475e9e6cd09SYanqin Li // uncache resp 47674050fc0SYanqin Li when (e.io.slaveId.valid && e.io.slaveId.bits === io.uncache.resp.bits.id) { 477e9e6cd09SYanqin Li e.io.uncache.resp <> io.uncache.resp 478e9e6cd09SYanqin Li } 479e9e6cd09SYanqin Li 480e9e6cd09SYanqin Li } 481e9e6cd09SYanqin Li 482e9e6cd09SYanqin Li mmioReq.ready := false.B 483e9e6cd09SYanqin Li ncReqArb.io.out.ready := false.B 484e9e6cd09SYanqin Li when(mmioSelect){ 485e9e6cd09SYanqin Li uncacheReq <> mmioReq 486e9e6cd09SYanqin Li }.otherwise{ 487e9e6cd09SYanqin Li uncacheReq <> ncReqArb.io.out 488e9e6cd09SYanqin Li } 489e9e6cd09SYanqin Li 490e9e6cd09SYanqin Li // uncache Request 491e9e6cd09SYanqin Li AddPipelineReg(uncacheReq, io.uncache.req, false.B) 492e9e6cd09SYanqin Li 493e9e6cd09SYanqin Li // uncache Writeback 494e9e6cd09SYanqin Li AddPipelineReg(mmioOut, io.mmioOut(UncacheWBPort), false.B) 495e9e6cd09SYanqin Li io.mmioRawData(UncacheWBPort) := RegEnable(mmioRawData, mmioOut.fire) 496e9e6cd09SYanqin Li 497e9e6cd09SYanqin Li (0 until LoadPipelineWidth).foreach { i => AddPipelineReg(ncOut(i), io.ncOut(i), false.B) } 498e9e6cd09SYanqin Li 499e9e6cd09SYanqin Li // uncache exception 500e9e6cd09SYanqin Li io.exception.valid := Cat(entries.map(_.io.exception.valid)).orR 501e9e6cd09SYanqin Li io.exception.bits := ParallelPriorityMux(entries.map(e => 502e9e6cd09SYanqin Li (e.io.exception.valid, e.io.exception.bits) 503e9e6cd09SYanqin Li )) 504e9e6cd09SYanqin Li 505e9e6cd09SYanqin Li // rob 506e9e6cd09SYanqin Li for (i <- 0 until LoadPipelineWidth) { 507e9e6cd09SYanqin Li io.rob.mmio(i) := RegNext(s1_valid(i) && s1_req(i).mmio) 508e9e6cd09SYanqin Li io.rob.uop(i) := RegEnable(s1_req(i).uop, s1_valid(i)) 509e9e6cd09SYanqin Li } 510e9e6cd09SYanqin Li 511e9e6cd09SYanqin Li 512e9e6cd09SYanqin Li /****************************************************************** 513e9e6cd09SYanqin Li * Deallocate 514e9e6cd09SYanqin Li ******************************************************************/ 515e9e6cd09SYanqin Li // UncacheBuffer deallocate 516e9e6cd09SYanqin Li val freeMaskVec = Wire(Vec(LoadUncacheBufferSize, Bool())) 517e9e6cd09SYanqin Li 518e9e6cd09SYanqin Li // init 519e9e6cd09SYanqin Li freeMaskVec.map(e => e := false.B) 520e9e6cd09SYanqin Li 521e9e6cd09SYanqin Li // dealloc logic 522e9e6cd09SYanqin Li entries.zipWithIndex.foreach { 523e9e6cd09SYanqin Li case (e, i) => 524e9e6cd09SYanqin Li when ((e.io.mmioSelect && e.io.mmioOut.fire) || e.io.ncOut.fire || e.io.flush) { 525e9e6cd09SYanqin Li freeMaskVec(i) := true.B 526e9e6cd09SYanqin Li } 527e9e6cd09SYanqin Li } 528e9e6cd09SYanqin Li 529e9e6cd09SYanqin Li freeList.io.free := freeMaskVec.asUInt 530e9e6cd09SYanqin Li 531e9e6cd09SYanqin Li 532e9e6cd09SYanqin Li /****************************************************************** 533e9e6cd09SYanqin Li * Uncache rollback detection 534e9e6cd09SYanqin Li * 535e9e6cd09SYanqin Li * When uncache loads enqueue, it searches uncache loads, They can not enqueue and need re-execution. 536e9e6cd09SYanqin Li * 537e9e6cd09SYanqin Li * Cycle 0: uncache enqueue. 538e9e6cd09SYanqin Li * Cycle 1: Select oldest uncache loads. 539e9e6cd09SYanqin Li * Cycle 2: Redirect Fire. 540e9e6cd09SYanqin Li * Choose the oldest load from LoadPipelineWidth oldest loads. 541e9e6cd09SYanqin Li * Prepare redirect request according to the detected rejection. 542e9e6cd09SYanqin Li * Fire redirect request (if valid) 543e9e6cd09SYanqin Li * 544e9e6cd09SYanqin Li * Load_S3 .... Load_S3 545e9e6cd09SYanqin Li * stage 0: lq lq 546e9e6cd09SYanqin Li * | | (can not enqueue) 547e9e6cd09SYanqin Li * stage 1: lq lq 548e9e6cd09SYanqin Li * | | 549e9e6cd09SYanqin Li * --------------- 550e9e6cd09SYanqin Li * | 551e9e6cd09SYanqin Li * stage 2: lq 552e9e6cd09SYanqin Li * | 553e9e6cd09SYanqin Li * rollback req 554e9e6cd09SYanqin Li * 555e9e6cd09SYanqin Li ******************************************************************/ 556e9e6cd09SYanqin Li def selectOldestRedirect(xs: Seq[Valid[Redirect]]): Vec[Bool] = { 557e9e6cd09SYanqin Li val compareVec = (0 until xs.length).map(i => (0 until i).map(j => isAfter(xs(j).bits.robIdx, xs(i).bits.robIdx))) 558e9e6cd09SYanqin Li val resultOnehot = VecInit((0 until xs.length).map(i => Cat((0 until xs.length).map(j => 559e9e6cd09SYanqin Li (if (j < i) !xs(j).valid || compareVec(i)(j) 560e9e6cd09SYanqin Li else if (j == i) xs(i).valid 561e9e6cd09SYanqin Li else !xs(j).valid || !compareVec(j)(i)) 562e9e6cd09SYanqin Li )).andR)) 563e9e6cd09SYanqin Li resultOnehot 564e9e6cd09SYanqin Li } 565e9e6cd09SYanqin Li val reqNeedCheck = VecInit((0 until LoadPipelineWidth).map(w => 566e9e6cd09SYanqin Li s2_enqueue(w) && !s2_enqValidVec(w) 567e9e6cd09SYanqin Li )) 568e9e6cd09SYanqin Li val reqSelUops = VecInit(s2_req.map(_.uop)) 569e9e6cd09SYanqin Li val allRedirect = (0 until LoadPipelineWidth).map(i => { 570e9e6cd09SYanqin Li val redirect = Wire(Valid(new Redirect)) 571e9e6cd09SYanqin Li redirect.valid := reqNeedCheck(i) 572e9e6cd09SYanqin Li redirect.bits := DontCare 573e9e6cd09SYanqin Li redirect.bits.isRVC := reqSelUops(i).preDecodeInfo.isRVC 574e9e6cd09SYanqin Li redirect.bits.robIdx := reqSelUops(i).robIdx 575e9e6cd09SYanqin Li redirect.bits.ftqIdx := reqSelUops(i).ftqPtr 576e9e6cd09SYanqin Li redirect.bits.ftqOffset := reqSelUops(i).ftqOffset 577e9e6cd09SYanqin Li redirect.bits.level := RedirectLevel.flush 578e9e6cd09SYanqin Li redirect.bits.cfiUpdate.target := reqSelUops(i).pc // TODO: check if need pc 579e9e6cd09SYanqin Li redirect.bits.debug_runahead_checkpoint_id := reqSelUops(i).debugInfo.runahead_checkpoint_id 580e9e6cd09SYanqin Li redirect 581e9e6cd09SYanqin Li }) 582e9e6cd09SYanqin Li val oldestOneHot = selectOldestRedirect(allRedirect) 583e9e6cd09SYanqin Li val oldestRedirect = Mux1H(oldestOneHot, allRedirect) 584e9e6cd09SYanqin Li val lastCycleRedirect = Wire(Valid(new Redirect)) 585e9e6cd09SYanqin Li lastCycleRedirect.valid := RegNext(io.redirect.valid) 586e9e6cd09SYanqin Li lastCycleRedirect.bits := RegEnable(io.redirect.bits, io.redirect.valid) 587e9e6cd09SYanqin Li val lastLastCycleRedirect = Wire(Valid(new Redirect)) 588e9e6cd09SYanqin Li lastLastCycleRedirect.valid := RegNext(lastCycleRedirect.valid) 589e9e6cd09SYanqin Li lastLastCycleRedirect.bits := RegEnable(lastCycleRedirect.bits, lastCycleRedirect.valid) 590e9e6cd09SYanqin Li io.rollback.valid := GatedValidRegNext(oldestRedirect.valid && 591e9e6cd09SYanqin Li !oldestRedirect.bits.robIdx.needFlush(io.redirect) && 592e9e6cd09SYanqin Li !oldestRedirect.bits.robIdx.needFlush(lastCycleRedirect) && 593e9e6cd09SYanqin Li !oldestRedirect.bits.robIdx.needFlush(lastLastCycleRedirect)) 594e9e6cd09SYanqin Li io.rollback.bits := RegEnable(oldestRedirect.bits, oldestRedirect.valid) 595e9e6cd09SYanqin Li 596e9e6cd09SYanqin Li 597e9e6cd09SYanqin Li /****************************************************************** 598e9e6cd09SYanqin Li * Perf Counter 599e9e6cd09SYanqin Li ******************************************************************/ 600e9e6cd09SYanqin Li val validCount = freeList.io.validCount 601e9e6cd09SYanqin Li val allowEnqueue = !freeList.io.empty 602e9e6cd09SYanqin Li QueuePerf(LoadUncacheBufferSize, validCount, !allowEnqueue) 603e9e6cd09SYanqin Li 604e9e6cd09SYanqin Li XSPerfAccumulate("mmio_uncache_req", io.uncache.req.fire && !io.uncache.req.bits.nc) 605e9e6cd09SYanqin Li XSPerfAccumulate("mmio_writeback_success", io.mmioOut(0).fire) 606e9e6cd09SYanqin Li XSPerfAccumulate("mmio_writeback_blocked", io.mmioOut(0).valid && !io.mmioOut(0).ready) 607e9e6cd09SYanqin Li XSPerfAccumulate("nc_uncache_req", io.uncache.req.fire && io.uncache.req.bits.nc) 608e9e6cd09SYanqin Li XSPerfAccumulate("nc_writeback_success", io.ncOut(0).fire) 609e9e6cd09SYanqin Li XSPerfAccumulate("nc_writeback_blocked", io.ncOut(0).valid && !io.ncOut(0).ready) 610e9e6cd09SYanqin Li XSPerfAccumulate("uncache_full_rollback", io.rollback.valid) 611e9e6cd09SYanqin Li 612e9e6cd09SYanqin Li val perfEvents: Seq[(String, UInt)] = Seq( 613e9e6cd09SYanqin Li ("mmio_uncache_req", io.uncache.req.fire && !io.uncache.req.bits.nc), 614e9e6cd09SYanqin Li ("mmio_writeback_success", io.mmioOut(0).fire), 615e9e6cd09SYanqin Li ("mmio_writeback_blocked", io.mmioOut(0).valid && !io.mmioOut(0).ready), 616e9e6cd09SYanqin Li ("nc_uncache_req", io.uncache.req.fire && io.uncache.req.bits.nc), 617e9e6cd09SYanqin Li ("nc_writeback_success", io.ncOut(0).fire), 618e9e6cd09SYanqin Li ("nc_writeback_blocked", io.ncOut(0).valid && !io.ncOut(0).ready), 619e9e6cd09SYanqin Li ("uncache_full_rollback", io.rollback.valid) 620e9e6cd09SYanqin Li ) 621e9e6cd09SYanqin Li // end 622e9e6cd09SYanqin Li} 623