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 { 145 146 val clientParameters = TLMasterPortParameters.v1( 147 clients = Seq(TLMasterParameters.v1( 148 "uncache", 149 sourceId = IdRange(0, 1) 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 HasTLDump 161{ 162 val io = IO(new UncacheIO) 163 164 val (bus, edge) = outer.clientNode.out.head 165 166 val resp_arb = Module(new Arbiter(new DCacheWordResp, 1)) 167 168 val req = io.lsq.req 169 val resp = io.lsq.resp 170 val mem_acquire = bus.a 171 val mem_grant = bus.d 172 173 val entry_alloc_idx = Wire(UInt()) 174 val req_ready = WireInit(false.B) 175 176 // assign default values to output signals 177 bus.b.ready := false.B 178 bus.c.valid := false.B 179 bus.c.bits := DontCare 180 bus.d.ready := false.B 181 bus.e.valid := false.B 182 bus.e.bits := DontCare 183 184 //TODO: rewrite following code since we only have 1 entry 185 val entries = (0 until 1) map { i => 186 val entry = Module(new MMIOEntry(edge)) 187 188 entry.io.id := i.U(1.W) 189 190 // entry req 191 entry.io.req.valid := (i.U === entry_alloc_idx) && req.valid 192 entry.io.req.bits := req.bits 193 when (i.U === entry_alloc_idx) { 194 req_ready := entry.io.req.ready 195 } 196 197 // entry resp 198 resp_arb.io.in(i) <> entry.io.resp 199 200 entry.io.mem_grant.valid := false.B 201 entry.io.mem_grant.bits := DontCare 202 when (mem_grant.bits.source === i.U) { 203 entry.io.mem_grant <> mem_grant 204 } 205 entry 206 } 207 208 entry_alloc_idx := PriorityEncoder(entries.map(m=>m.io.req.ready)) 209 210 req.ready := req_ready 211 resp <> resp_arb.io.out 212 TLArbiter.lowestFromSeq(edge, mem_acquire, entries.map(_.io.mem_acquire)) 213 214 215 // print all input/output requests for debug purpose 216 217 // print req/resp 218 XSDebug(req.fire(), "req cmd: %x addr: %x data: %x mask: %x\n", 219 req.bits.cmd, req.bits.addr, req.bits.data, req.bits.mask) 220 XSDebug(resp.fire(), "data: %x\n", req.bits.data) 221 222 // print tilelink messages 223 when(mem_acquire.valid){ 224 XSDebug("mem_acquire valid, ready=%d ", mem_acquire.ready) 225 mem_acquire.bits.dump 226 } 227 when (mem_grant.fire()) { 228 XSDebug("mem_grant fire ") 229 mem_grant.bits.dump 230 } 231} 232