1/*************************************************************************************** 2* Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC) 3* Copyright (c) 2020-2024 Institute of Computing Technology, Chinese Academy of Sciences 4* Copyright (c) 2020-2021 Peng Cheng Laboratory 5* 6* XiangShan is licensed under Mulan PSL v2. 7* You can use this software according to the terms and conditions of the Mulan PSL v2. 8* You may obtain a copy of Mulan PSL v2 at: 9* http://license.coscl.org.cn/MulanPSL2 10* 11* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 12* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 13* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 14* 15* See the Mulan PSL v2 for more details. 16***************************************************************************************/ 17 18package xiangshan.frontend.icache 19 20import chisel3._ 21import chisel3.util._ 22import freechips.rocketchip.diplomacy.IdRange 23import freechips.rocketchip.diplomacy.LazyModule 24import freechips.rocketchip.diplomacy.LazyModuleImp 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 utils._ 34import xiangshan.frontend._ 35 36class InsUncacheReq(implicit p: Parameters) extends ICacheBundle { 37 val addr: UInt = UInt(PAddrBits.W) 38} 39 40class InsUncacheResp(implicit p: Parameters) extends ICacheBundle { 41 val data: UInt = UInt(maxInstrLen.W) 42} 43 44class InstrMMIOEntryIO(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheBundle { 45 val id: UInt = Input(UInt(log2Up(cacheParams.nMMIOs).W)) 46 // client requests 47 val req: DecoupledIO[InsUncacheReq] = Flipped(DecoupledIO(new InsUncacheReq)) 48 val resp: DecoupledIO[InsUncacheResp] = DecoupledIO(new InsUncacheResp) 49 50 val mmio_acquire: DecoupledIO[TLBundleA] = DecoupledIO(new TLBundleA(edge.bundle)) 51 val mmio_grant: DecoupledIO[TLBundleD] = Flipped(DecoupledIO(new TLBundleD(edge.bundle))) 52 53 val flush: Bool = Input(Bool()) 54} 55 56// One miss entry deals with one mmio request 57class InstrMMIOEntry(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheModule with HasIFUConst { 58 val io: InstrMMIOEntryIO = IO(new InstrMMIOEntryIO(edge)) 59 60 private val s_invalid :: s_refill_req :: s_refill_resp :: s_send_resp :: Nil = Enum(4) 61 62 private val state = RegInit(s_invalid) 63 64 private val req = Reg(new InsUncacheReq) 65 private val respDataReg = Reg(UInt(mmioBusWidth.W)) 66 67 // assign default values to output signals 68 io.req.ready := false.B 69 io.resp.valid := false.B 70 io.resp.bits := DontCare 71 72 io.mmio_acquire.valid := false.B 73 io.mmio_acquire.bits := DontCare 74 75 io.mmio_grant.ready := false.B 76 77 private val needFlush = RegInit(false.B) 78 79 when(io.flush && (state =/= s_invalid) && (state =/= s_send_resp))(needFlush := true.B) 80 .elsewhen((state === s_send_resp) && needFlush)(needFlush := false.B) 81 82 // -------------------------------------------- 83 // s_invalid: receive requests 84 when(state === s_invalid) { 85 io.req.ready := true.B 86 87 when(io.req.fire) { 88 req := io.req.bits 89 state := s_refill_req 90 } 91 } 92 93 when(state === s_refill_req) { 94 val address_aligned = req.addr(req.addr.getWidth - 1, log2Ceil(mmioBusBytes)) 95 io.mmio_acquire.valid := true.B 96 io.mmio_acquire.bits := edge.Get( 97 fromSource = io.id, 98 toAddress = Cat(address_aligned, 0.U(log2Ceil(mmioBusBytes).W)), 99 lgSize = log2Ceil(mmioBusBytes).U 100 )._2 101 102 when(io.mmio_acquire.fire) { 103 state := s_refill_resp 104 } 105 } 106 107 val (_, _, refill_done, _) = edge.addr_inc(io.mmio_grant) 108 109 when(state === s_refill_resp) { 110 io.mmio_grant.ready := true.B 111 112 when(io.mmio_grant.fire) { 113 respDataReg := io.mmio_grant.bits.data 114 state := s_send_resp 115 } 116 } 117 118 private def getDataFromBus(pc: UInt): UInt = { 119 val respData = Wire(UInt(maxInstrLen.W)) 120 respData := Mux( 121 pc(2, 1) === "b00".U, 122 respDataReg(31, 0), 123 Mux( 124 pc(2, 1) === "b01".U, 125 respDataReg(47, 16), 126 Mux(pc(2, 1) === "b10".U, respDataReg(63, 32), Cat(0.U, respDataReg(63, 48))) 127 ) 128 ) 129 respData 130 } 131 132 when(state === s_send_resp) { 133 io.resp.valid := !needFlush 134 io.resp.bits.data := getDataFromBus(req.addr) 135 // metadata should go with the response 136 when(io.resp.fire || needFlush) { 137 state := s_invalid 138 } 139 } 140} 141 142class InstrUncacheIO(implicit p: Parameters) extends ICacheBundle { 143 val req: DecoupledIO[InsUncacheReq] = Flipped(DecoupledIO(new InsUncacheReq)) 144 val resp: DecoupledIO[InsUncacheResp] = DecoupledIO(new InsUncacheResp) 145 val flush: Bool = Input(Bool()) 146} 147 148class InstrUncache()(implicit p: Parameters) extends LazyModule with HasICacheParameters { 149 override def shouldBeInlined: Boolean = false 150 151 val clientParameters: TLMasterPortParameters = TLMasterPortParameters.v1( 152 clients = Seq(TLMasterParameters.v1( 153 "InstrUncache", 154 sourceId = IdRange(0, cacheParams.nMMIOs) 155 )) 156 ) 157 val clientNode: TLClientNode = TLClientNode(Seq(clientParameters)) 158 159 lazy val module: InstrUncacheImp = new InstrUncacheImp(this) 160} 161 162class InstrUncacheImp(outer: InstrUncache) 163 extends LazyModuleImp(outer) 164 with HasICacheParameters 165 with HasTLDump { 166 val io: InstrUncacheIO = IO(new InstrUncacheIO) 167 168 private val (bus, edge) = outer.clientNode.out.head 169 170 private val resp_arb = Module(new Arbiter(new InsUncacheResp, cacheParams.nMMIOs)) 171 172 private val req = io.req 173 private val resp = io.resp 174 private val mmio_acquire = bus.a 175 private val mmio_grant = bus.d 176 177 private val entry_alloc_idx = Wire(UInt()) 178 private val req_ready = WireInit(false.B) 179 180 // assign default values to output signals 181 bus.b.ready := false.B 182 bus.c.valid := false.B 183 bus.c.bits := DontCare 184 bus.d.ready := false.B 185 bus.e.valid := false.B 186 bus.e.bits := DontCare 187 188 private val entries = (0 until cacheParams.nMMIOs).map { i => 189 val entry = Module(new InstrMMIOEntry(edge)) 190 191 entry.io.id := i.U(log2Up(cacheParams.nMMIOs).W) 192 entry.io.flush := io.flush 193 194 // entry req 195 entry.io.req.valid := (i.U === entry_alloc_idx) && req.valid 196 entry.io.req.bits := req.bits 197 when(i.U === entry_alloc_idx) { 198 req_ready := entry.io.req.ready 199 } 200 201 // entry resp 202 resp_arb.io.in(i) <> entry.io.resp 203 204 entry.io.mmio_grant.valid := false.B 205 entry.io.mmio_grant.bits := DontCare 206 when(mmio_grant.bits.source === i.U) { 207 entry.io.mmio_grant <> mmio_grant 208 } 209 entry 210 } 211 212 entry_alloc_idx := PriorityEncoder(entries.map(m => m.io.req.ready)) 213 214 req.ready := req_ready 215 resp <> resp_arb.io.out 216 TLArbiter.lowestFromSeq(edge, mmio_acquire, entries.map(_.io.mmio_acquire)) 217} 218