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