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