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