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