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.frontend.icache 18 19import chisel3._ 20import chisel3.util._ 21import utils._ 22import utility._ 23import org.chipsalliance.cde.config.Parameters 24import freechips.rocketchip.diplomacy.{IdRange, LazyModule, LazyModuleImp, TransferSizes} 25import freechips.rocketchip.tilelink.{TLArbiter, TLBundleA, TLBundleD, TLClientNode, TLEdgeOut, TLMasterParameters, TLMasterPortParameters} 26import xiangshan._ 27import xiangshan.frontend._ 28 29class InsUncacheReq(implicit p: Parameters) extends ICacheBundle 30{ 31 val addr = UInt(PAddrBits.W) 32} 33 34class InsUncacheResp(implicit p: Parameters) extends ICacheBundle 35{ 36 val data = UInt(maxInstrLen.W) 37} 38 39// One miss entry deals with one mmio request 40class InstrMMIOEntry(edge: TLEdgeOut)(implicit p: Parameters) extends XSModule with HasICacheParameters with HasIFUConst 41{ 42 val io = IO(new Bundle { 43 val id = Input(UInt(log2Up(cacheParams.nMMIOs).W)) 44 // client requests 45 val req = Flipped(DecoupledIO(new InsUncacheReq)) 46 val resp = DecoupledIO(new InsUncacheResp) 47 48 val mmio_acquire = DecoupledIO(new TLBundleA(edge.bundle)) 49 val mmio_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle))) 50 51 val flush = Input(Bool()) 52 }) 53 54 55 val s_invalid :: s_refill_req :: s_refill_resp :: s_send_resp :: Nil = Enum(4) 56 57 val state = RegInit(s_invalid) 58 59 val req = Reg(new InsUncacheReq ) 60 val respDataReg = Reg(UInt(mmioBusWidth.W)) 61 62 // assign default values to output signals 63 io.req.ready := false.B 64 io.resp.valid := false.B 65 io.resp.bits := DontCare 66 67 io.mmio_acquire.valid := false.B 68 io.mmio_acquire.bits := DontCare 69 70 io.mmio_grant.ready := false.B 71 72 val needFlush = RegInit(false.B) 73 74 when(io.flush && (state =/= s_invalid) && (state =/= s_send_resp)){ needFlush := true.B } 75 .elsewhen((state=== s_send_resp) && needFlush){ needFlush := false.B } 76 77 // -------------------------------------------- 78 // s_invalid: receive requests 79 when (state === s_invalid) { 80 io.req.ready := true.B 81 82 when (io.req.fire) { 83 req := io.req.bits 84 state := s_refill_req 85 } 86 } 87 88 89 when (state === s_refill_req) { 90 val address_aligned = req.addr(req.addr.getWidth - 1, log2Ceil(mmioBusBytes)) 91 io.mmio_acquire.valid := true.B 92 io.mmio_acquire.bits := edge.Get( 93 fromSource = io.id, 94 toAddress = Cat(address_aligned, 0.U(log2Ceil(mmioBusBytes).W)), 95 lgSize = log2Ceil(mmioBusBytes).U 96 )._2 97 98 when (io.mmio_acquire.fire) { 99 state := s_refill_resp 100 } 101 } 102 103 val (_, _, refill_done, _) = edge.addr_inc(io.mmio_grant) 104 105 when (state === s_refill_resp) { 106 io.mmio_grant.ready := true.B 107 108 when (io.mmio_grant.fire) { 109 respDataReg := io.mmio_grant.bits.data 110 state := s_send_resp 111 } 112 } 113 114 def getDataFromBus(pc: UInt) = { 115 val respData = Wire(UInt(maxInstrLen.W)) 116 respData := Mux(pc(2,1) === "b00".U, respDataReg(31,0), 117 Mux(pc(2,1) === "b01".U, respDataReg(47,16), 118 Mux(pc(2,1) === "b10".U, respDataReg(63,32), 119 Cat(0.U, respDataReg(63,48)) 120 ) 121 ) 122 ) 123 respData 124 } 125 126 when (state === s_send_resp) { 127 io.resp.valid := !needFlush 128 io.resp.bits.data := getDataFromBus(req.addr) 129 // meta data should go with the response 130 when (io.resp.fire || needFlush) { 131 state := s_invalid 132 } 133 } 134} 135 136class InstrUncacheIO(implicit p: Parameters) extends ICacheBundle { 137 val req = Flipped(DecoupledIO(new InsUncacheReq )) 138 val resp = DecoupledIO(new InsUncacheResp) 139 val flush = Input(Bool()) 140} 141 142class InstrUncache()(implicit p: Parameters) extends LazyModule with HasICacheParameters { 143 override def shouldBeInlined: Boolean = false 144 145 val clientParameters = TLMasterPortParameters.v1( 146 clients = Seq(TLMasterParameters.v1( 147 "InstrUncache", 148 sourceId = IdRange(0, cacheParams.nMMIOs) 149 )) 150 ) 151 val clientNode = TLClientNode(Seq(clientParameters)) 152 153 lazy val module = new InstrUncacheImp(this) 154 155} 156 157class InstrUncacheImp(outer: InstrUncache) 158 extends LazyModuleImp(outer) 159 with HasICacheParameters 160 with HasTLDump 161{ 162 val io = IO(new InstrUncacheIO) 163 164 val (bus, edge) = outer.clientNode.out.head 165 166 val resp_arb = Module(new Arbiter(new InsUncacheResp, cacheParams.nMMIOs)) 167 168 val req = io.req 169 val resp = io.resp 170 val mmio_acquire = bus.a 171 val mmio_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 val entries = (0 until cacheParams.nMMIOs) map { i => 185 val entry = Module(new InstrMMIOEntry(edge)) 186 187 entry.io.id := i.U(log2Up(cacheParams.nMMIOs).W) 188 entry.io.flush := io.flush 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.mmio_grant.valid := false.B 201 entry.io.mmio_grant.bits := DontCare 202 when (mmio_grant.bits.source === i.U) { 203 entry.io.mmio_grant <> mmio_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, mmio_acquire, entries.map(_.io.mmio_acquire)) 213 214} 215