1*1f0e2dc7SJiawei Lin/*************************************************************************************** 2*1f0e2dc7SJiawei Lin* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3*1f0e2dc7SJiawei Lin* Copyright (c) 2020-2021 Peng Cheng Laboratory 4*1f0e2dc7SJiawei Lin* 5*1f0e2dc7SJiawei Lin* XiangShan is licensed under Mulan PSL v2. 6*1f0e2dc7SJiawei Lin* You can use this software according to the terms and conditions of the Mulan PSL v2. 7*1f0e2dc7SJiawei Lin* You may obtain a copy of Mulan PSL v2 at: 8*1f0e2dc7SJiawei Lin* http://license.coscl.org.cn/MulanPSL2 9*1f0e2dc7SJiawei Lin* 10*1f0e2dc7SJiawei Lin* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11*1f0e2dc7SJiawei Lin* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12*1f0e2dc7SJiawei Lin* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13*1f0e2dc7SJiawei Lin* 14*1f0e2dc7SJiawei Lin* See the Mulan PSL v2 for more details. 15*1f0e2dc7SJiawei Lin***************************************************************************************/ 16*1f0e2dc7SJiawei Lin 17*1f0e2dc7SJiawei Linpackage xiangshan.cache 18*1f0e2dc7SJiawei Lin 19*1f0e2dc7SJiawei Linimport chisel3._ 20*1f0e2dc7SJiawei Linimport chisel3.util._ 21*1f0e2dc7SJiawei Linimport utils.{HasTLDump, PriorityMuxWithFlag, XSDebug} 22*1f0e2dc7SJiawei Linimport chipsalliance.rocketchip.config.Parameters 23*1f0e2dc7SJiawei Linimport freechips.rocketchip.diplomacy.{IdRange, LazyModule, LazyModuleImp, TransferSizes} 24*1f0e2dc7SJiawei Linimport freechips.rocketchip.tilelink.{TLArbiter, TLBundleA, TLBundleD, TLClientNode, TLEdgeOut, TLMasterParameters, TLMasterPortParameters} 25*1f0e2dc7SJiawei Linimport xiangshan.{MicroOp, Redirect} 26*1f0e2dc7SJiawei Lin 27*1f0e2dc7SJiawei Lin// One miss entry deals with one mmio request 28*1f0e2dc7SJiawei Linclass MMIOEntry(edge: TLEdgeOut)(implicit p: Parameters) extends DCacheModule 29*1f0e2dc7SJiawei Lin{ 30*1f0e2dc7SJiawei Lin val io = IO(new Bundle { 31*1f0e2dc7SJiawei Lin // MSHR ID 32*1f0e2dc7SJiawei Lin val id = Input(UInt()) 33*1f0e2dc7SJiawei Lin 34*1f0e2dc7SJiawei Lin // client requests 35*1f0e2dc7SJiawei Lin val req = Flipped(DecoupledIO(new DCacheWordReq )) 36*1f0e2dc7SJiawei Lin val resp = DecoupledIO(new DCacheWordResp) 37*1f0e2dc7SJiawei Lin 38*1f0e2dc7SJiawei Lin val mem_acquire = DecoupledIO(new TLBundleA(edge.bundle)) 39*1f0e2dc7SJiawei Lin val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle))) 40*1f0e2dc7SJiawei Lin }) 41*1f0e2dc7SJiawei Lin 42*1f0e2dc7SJiawei Lin 43*1f0e2dc7SJiawei Lin val s_invalid :: s_refill_req :: s_refill_resp :: s_send_resp :: Nil = Enum(4) 44*1f0e2dc7SJiawei Lin 45*1f0e2dc7SJiawei Lin val state = RegInit(s_invalid) 46*1f0e2dc7SJiawei Lin 47*1f0e2dc7SJiawei Lin val req = Reg(new DCacheWordReq ) 48*1f0e2dc7SJiawei Lin val resp_data = Reg(UInt(DataBits.W)) 49*1f0e2dc7SJiawei Lin 50*1f0e2dc7SJiawei Lin 51*1f0e2dc7SJiawei Lin // assign default values to output signals 52*1f0e2dc7SJiawei Lin io.req.ready := false.B 53*1f0e2dc7SJiawei Lin io.resp.valid := false.B 54*1f0e2dc7SJiawei Lin io.resp.bits := DontCare 55*1f0e2dc7SJiawei Lin 56*1f0e2dc7SJiawei Lin io.mem_acquire.valid := false.B 57*1f0e2dc7SJiawei Lin io.mem_acquire.bits := DontCare 58*1f0e2dc7SJiawei Lin 59*1f0e2dc7SJiawei Lin io.mem_grant.ready := false.B 60*1f0e2dc7SJiawei Lin 61*1f0e2dc7SJiawei Lin 62*1f0e2dc7SJiawei Lin XSDebug("entry: %d state: %d\n", io.id, state) 63*1f0e2dc7SJiawei Lin // -------------------------------------------- 64*1f0e2dc7SJiawei Lin // s_invalid: receive requests 65*1f0e2dc7SJiawei Lin when (state === s_invalid) { 66*1f0e2dc7SJiawei Lin io.req.ready := true.B 67*1f0e2dc7SJiawei Lin 68*1f0e2dc7SJiawei Lin when (io.req.fire()) { 69*1f0e2dc7SJiawei Lin req := io.req.bits 70*1f0e2dc7SJiawei Lin req.addr := io.req.bits.addr 71*1f0e2dc7SJiawei Lin state := s_refill_req 72*1f0e2dc7SJiawei Lin } 73*1f0e2dc7SJiawei Lin } 74*1f0e2dc7SJiawei Lin 75*1f0e2dc7SJiawei Lin // -------------------------------------------- 76*1f0e2dc7SJiawei Lin // refill 77*1f0e2dc7SJiawei Lin // TODO: determine 'lgSize' in memend 78*1f0e2dc7SJiawei Lin val size = PopCount(req.mask) 79*1f0e2dc7SJiawei Lin val (lgSize, legal) = PriorityMuxWithFlag(Seq( 80*1f0e2dc7SJiawei Lin 1.U -> 0.U, 81*1f0e2dc7SJiawei Lin 2.U -> 1.U, 82*1f0e2dc7SJiawei Lin 4.U -> 2.U, 83*1f0e2dc7SJiawei Lin 8.U -> 3.U 84*1f0e2dc7SJiawei Lin ).map(m => (size===m._1) -> m._2)) 85*1f0e2dc7SJiawei Lin assert(!(io.mem_acquire.valid && !legal)) 86*1f0e2dc7SJiawei Lin 87*1f0e2dc7SJiawei Lin val load = edge.Get( 88*1f0e2dc7SJiawei Lin fromSource = io.id, 89*1f0e2dc7SJiawei Lin toAddress = req.addr, 90*1f0e2dc7SJiawei Lin lgSize = lgSize 91*1f0e2dc7SJiawei Lin )._2 92*1f0e2dc7SJiawei Lin 93*1f0e2dc7SJiawei Lin val store = edge.Put( 94*1f0e2dc7SJiawei Lin fromSource = io.id, 95*1f0e2dc7SJiawei Lin toAddress = req.addr, 96*1f0e2dc7SJiawei Lin lgSize = lgSize, 97*1f0e2dc7SJiawei Lin data = req.data, 98*1f0e2dc7SJiawei Lin mask = req.mask 99*1f0e2dc7SJiawei Lin )._2 100*1f0e2dc7SJiawei Lin 101*1f0e2dc7SJiawei Lin when (state === s_refill_req) { 102*1f0e2dc7SJiawei Lin io.mem_acquire.valid := true.B 103*1f0e2dc7SJiawei Lin io.mem_acquire.bits := Mux(req.cmd === MemoryOpConstants.M_XWR, store, load) 104*1f0e2dc7SJiawei Lin 105*1f0e2dc7SJiawei Lin when (io.mem_acquire.fire()) { 106*1f0e2dc7SJiawei Lin state := s_refill_resp 107*1f0e2dc7SJiawei Lin } 108*1f0e2dc7SJiawei Lin } 109*1f0e2dc7SJiawei Lin 110*1f0e2dc7SJiawei Lin val (_, _, refill_done, _) = edge.addr_inc(io.mem_grant) 111*1f0e2dc7SJiawei Lin 112*1f0e2dc7SJiawei Lin when (state === s_refill_resp) { 113*1f0e2dc7SJiawei Lin io.mem_grant.ready := true.B 114*1f0e2dc7SJiawei Lin 115*1f0e2dc7SJiawei Lin when (io.mem_grant.fire()) { 116*1f0e2dc7SJiawei Lin resp_data := io.mem_grant.bits.data 117*1f0e2dc7SJiawei Lin assert(refill_done, "MMIO response should be one beat only!") 118*1f0e2dc7SJiawei Lin state := s_send_resp 119*1f0e2dc7SJiawei Lin } 120*1f0e2dc7SJiawei Lin } 121*1f0e2dc7SJiawei Lin 122*1f0e2dc7SJiawei Lin // -------------------------------------------- 123*1f0e2dc7SJiawei Lin when (state === s_send_resp) { 124*1f0e2dc7SJiawei Lin io.resp.valid := true.B 125*1f0e2dc7SJiawei Lin io.resp.bits.data := resp_data 126*1f0e2dc7SJiawei Lin // meta data should go with the response 127*1f0e2dc7SJiawei Lin io.resp.bits.id := req.id 128*1f0e2dc7SJiawei Lin io.resp.bits.miss := false.B 129*1f0e2dc7SJiawei Lin io.resp.bits.replay := false.B 130*1f0e2dc7SJiawei Lin 131*1f0e2dc7SJiawei Lin when (io.resp.fire()) { 132*1f0e2dc7SJiawei Lin state := s_invalid 133*1f0e2dc7SJiawei Lin } 134*1f0e2dc7SJiawei Lin } 135*1f0e2dc7SJiawei Lin} 136*1f0e2dc7SJiawei Lin 137*1f0e2dc7SJiawei Linclass UncacheIO(implicit p: Parameters) extends DCacheBundle { 138*1f0e2dc7SJiawei Lin val lsq = Flipped(new DCacheWordIO) 139*1f0e2dc7SJiawei Lin} 140*1f0e2dc7SJiawei Lin 141*1f0e2dc7SJiawei Lin// convert DCacheIO to TileLink 142*1f0e2dc7SJiawei Lin// for Now, we only deal with TL-UL 143*1f0e2dc7SJiawei Lin 144*1f0e2dc7SJiawei Linclass Uncache()(implicit p: Parameters) extends LazyModule with HasDCacheParameters { 145*1f0e2dc7SJiawei Lin 146*1f0e2dc7SJiawei Lin val clientParameters = TLMasterPortParameters.v1( 147*1f0e2dc7SJiawei Lin clients = Seq(TLMasterParameters.v1( 148*1f0e2dc7SJiawei Lin "uncache", 149*1f0e2dc7SJiawei Lin sourceId = IdRange(0, cfg.nMMIOEntries) 150*1f0e2dc7SJiawei Lin )) 151*1f0e2dc7SJiawei Lin ) 152*1f0e2dc7SJiawei Lin val clientNode = TLClientNode(Seq(clientParameters)) 153*1f0e2dc7SJiawei Lin 154*1f0e2dc7SJiawei Lin lazy val module = new UncacheImp(this) 155*1f0e2dc7SJiawei Lin 156*1f0e2dc7SJiawei Lin} 157*1f0e2dc7SJiawei Lin 158*1f0e2dc7SJiawei Linclass UncacheImp(outer: Uncache) 159*1f0e2dc7SJiawei Lin extends LazyModuleImp(outer) 160*1f0e2dc7SJiawei Lin with HasDCacheParameters 161*1f0e2dc7SJiawei Lin with HasTLDump 162*1f0e2dc7SJiawei Lin{ 163*1f0e2dc7SJiawei Lin val io = IO(new UncacheIO) 164*1f0e2dc7SJiawei Lin 165*1f0e2dc7SJiawei Lin val (bus, edge) = outer.clientNode.out.head 166*1f0e2dc7SJiawei Lin require(bus.d.bits.data.getWidth == wordBits, "Uncache: tilelink width does not match") 167*1f0e2dc7SJiawei Lin 168*1f0e2dc7SJiawei Lin val resp_arb = Module(new Arbiter(new DCacheWordResp, cfg.nMMIOEntries)) 169*1f0e2dc7SJiawei Lin 170*1f0e2dc7SJiawei Lin val req = io.lsq.req 171*1f0e2dc7SJiawei Lin val resp = io.lsq.resp 172*1f0e2dc7SJiawei Lin val mem_acquire = bus.a 173*1f0e2dc7SJiawei Lin val mem_grant = bus.d 174*1f0e2dc7SJiawei Lin 175*1f0e2dc7SJiawei Lin val entry_alloc_idx = Wire(UInt()) 176*1f0e2dc7SJiawei Lin val req_ready = WireInit(false.B) 177*1f0e2dc7SJiawei Lin 178*1f0e2dc7SJiawei Lin // assign default values to output signals 179*1f0e2dc7SJiawei Lin bus.b.ready := false.B 180*1f0e2dc7SJiawei Lin bus.c.valid := false.B 181*1f0e2dc7SJiawei Lin bus.c.bits := DontCare 182*1f0e2dc7SJiawei Lin bus.d.ready := false.B 183*1f0e2dc7SJiawei Lin bus.e.valid := false.B 184*1f0e2dc7SJiawei Lin bus.e.bits := DontCare 185*1f0e2dc7SJiawei Lin 186*1f0e2dc7SJiawei Lin val entries = (0 until cfg.nMMIOEntries) map { i => 187*1f0e2dc7SJiawei Lin val entry = Module(new MMIOEntry(edge)) 188*1f0e2dc7SJiawei Lin 189*1f0e2dc7SJiawei Lin entry.io.id := i.U(log2Up(cfg.nMMIOEntries).W) 190*1f0e2dc7SJiawei Lin 191*1f0e2dc7SJiawei Lin // entry req 192*1f0e2dc7SJiawei Lin entry.io.req.valid := (i.U === entry_alloc_idx) && req.valid 193*1f0e2dc7SJiawei Lin entry.io.req.bits := req.bits 194*1f0e2dc7SJiawei Lin when (i.U === entry_alloc_idx) { 195*1f0e2dc7SJiawei Lin req_ready := entry.io.req.ready 196*1f0e2dc7SJiawei Lin } 197*1f0e2dc7SJiawei Lin 198*1f0e2dc7SJiawei Lin // entry resp 199*1f0e2dc7SJiawei Lin resp_arb.io.in(i) <> entry.io.resp 200*1f0e2dc7SJiawei Lin 201*1f0e2dc7SJiawei Lin entry.io.mem_grant.valid := false.B 202*1f0e2dc7SJiawei Lin entry.io.mem_grant.bits := DontCare 203*1f0e2dc7SJiawei Lin when (mem_grant.bits.source === i.U) { 204*1f0e2dc7SJiawei Lin entry.io.mem_grant <> mem_grant 205*1f0e2dc7SJiawei Lin } 206*1f0e2dc7SJiawei Lin entry 207*1f0e2dc7SJiawei Lin } 208*1f0e2dc7SJiawei Lin 209*1f0e2dc7SJiawei Lin entry_alloc_idx := PriorityEncoder(entries.map(m=>m.io.req.ready)) 210*1f0e2dc7SJiawei Lin 211*1f0e2dc7SJiawei Lin req.ready := req_ready 212*1f0e2dc7SJiawei Lin resp <> resp_arb.io.out 213*1f0e2dc7SJiawei Lin TLArbiter.lowestFromSeq(edge, mem_acquire, entries.map(_.io.mem_acquire)) 214*1f0e2dc7SJiawei Lin 215*1f0e2dc7SJiawei Lin 216*1f0e2dc7SJiawei Lin // print all input/output requests for debug purpose 217*1f0e2dc7SJiawei Lin 218*1f0e2dc7SJiawei Lin // print req/resp 219*1f0e2dc7SJiawei Lin XSDebug(req.fire(), "req cmd: %x addr: %x data: %x mask: %x\n", 220*1f0e2dc7SJiawei Lin req.bits.cmd, req.bits.addr, req.bits.data, req.bits.mask) 221*1f0e2dc7SJiawei Lin XSDebug(resp.fire(), "data: %x\n", req.bits.data) 222*1f0e2dc7SJiawei Lin 223*1f0e2dc7SJiawei Lin // print tilelink messages 224*1f0e2dc7SJiawei Lin when(mem_acquire.valid){ 225*1f0e2dc7SJiawei Lin XSDebug("mem_acquire valid, ready=%d ", mem_acquire.ready) 226*1f0e2dc7SJiawei Lin mem_acquire.bits.dump 227*1f0e2dc7SJiawei Lin } 228*1f0e2dc7SJiawei Lin when (mem_grant.fire()) { 229*1f0e2dc7SJiawei Lin XSDebug("mem_grant fire ") 230*1f0e2dc7SJiawei Lin mem_grant.bits.dump 231*1f0e2dc7SJiawei Lin } 232*1f0e2dc7SJiawei Lin} 233