xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/InstrUncache.scala (revision 95e60e556aad1ea6d9a751adb912d97fe95ac938)
11d8f4dcbSJay/***************************************************************************************
21d8f4dcbSJay* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
31d8f4dcbSJay* Copyright (c) 2020-2021 Peng Cheng Laboratory
41d8f4dcbSJay*
51d8f4dcbSJay* XiangShan is licensed under Mulan PSL v2.
61d8f4dcbSJay* You can use this software according to the terms and conditions of the Mulan PSL v2.
71d8f4dcbSJay* You may obtain a copy of Mulan PSL v2 at:
81d8f4dcbSJay*          http://license.coscl.org.cn/MulanPSL2
91d8f4dcbSJay*
101d8f4dcbSJay* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
111d8f4dcbSJay* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
121d8f4dcbSJay* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
131d8f4dcbSJay*
141d8f4dcbSJay* See the Mulan PSL v2 for more details.
151d8f4dcbSJay***************************************************************************************/
161d8f4dcbSJay
171d8f4dcbSJaypackage xiangshan.frontend.icache
181d8f4dcbSJay
191d8f4dcbSJayimport chisel3._
201d8f4dcbSJayimport chisel3.util._
211d8f4dcbSJayimport utils._
223c02ee8fSwakafaimport utility._
231d8f4dcbSJayimport chipsalliance.rocketchip.config.Parameters
241d8f4dcbSJayimport freechips.rocketchip.diplomacy.{IdRange, LazyModule, LazyModuleImp, TransferSizes}
251d8f4dcbSJayimport freechips.rocketchip.tilelink.{TLArbiter, TLBundleA, TLBundleD, TLClientNode, TLEdgeOut, TLMasterParameters, TLMasterPortParameters}
261d8f4dcbSJayimport xiangshan._
271d8f4dcbSJayimport xiangshan.frontend._
281d8f4dcbSJay
291d8f4dcbSJayclass InsUncacheReq(implicit p: Parameters) extends ICacheBundle
301d8f4dcbSJay{
311d8f4dcbSJay    val addr = UInt(PAddrBits.W)
321d8f4dcbSJay}
331d8f4dcbSJay
341d8f4dcbSJayclass InsUncacheResp(implicit p: Parameters) extends ICacheBundle
351d8f4dcbSJay{
361d8f4dcbSJay  val data = UInt(maxInstrLen.W)
371d8f4dcbSJay}
381d8f4dcbSJay
391d8f4dcbSJay// One miss entry deals with one mmio request
401d8f4dcbSJayclass InstrMMIOEntry(edge: TLEdgeOut)(implicit p: Parameters) extends XSModule with HasICacheParameters with HasIFUConst
411d8f4dcbSJay{
421d8f4dcbSJay  val io = IO(new Bundle {
431d8f4dcbSJay    val id = Input(UInt(log2Up(cacheParams.nMMIOs).W))
441d8f4dcbSJay    // client requests
451d8f4dcbSJay    val req = Flipped(DecoupledIO(new InsUncacheReq))
461d8f4dcbSJay    val resp = DecoupledIO(new InsUncacheResp)
471d8f4dcbSJay
481d8f4dcbSJay    val mmio_acquire = DecoupledIO(new TLBundleA(edge.bundle))
491d8f4dcbSJay    val mmio_grant   = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
501d8f4dcbSJay
511d8f4dcbSJay    val flush = Input(Bool())
521d8f4dcbSJay  })
531d8f4dcbSJay
541d8f4dcbSJay
551d8f4dcbSJay  val s_invalid :: s_refill_req :: s_refill_resp :: s_send_resp :: Nil = Enum(4)
561d8f4dcbSJay
571d8f4dcbSJay  val state = RegInit(s_invalid)
581d8f4dcbSJay
591d8f4dcbSJay  val req       = Reg(new InsUncacheReq )
601d8f4dcbSJay  val respDataReg = Reg(UInt(mmioBusWidth.W))
611d8f4dcbSJay
621d8f4dcbSJay  // assign default values to output signals
631d8f4dcbSJay  io.req.ready           := false.B
641d8f4dcbSJay  io.resp.valid          := false.B
651d8f4dcbSJay  io.resp.bits           := DontCare
661d8f4dcbSJay
671d8f4dcbSJay  io.mmio_acquire.valid   := false.B
681d8f4dcbSJay  io.mmio_acquire.bits    := DontCare
691d8f4dcbSJay
701d8f4dcbSJay  io.mmio_grant.ready     := false.B
711d8f4dcbSJay
721d8f4dcbSJay  val needFlush = RegInit(false.B)
731d8f4dcbSJay
741d8f4dcbSJay  when(io.flush && (state =/= s_invalid) && (state =/= s_send_resp)){ needFlush := true.B }
751d8f4dcbSJay  .elsewhen((state=== s_send_resp) && needFlush){ needFlush := false.B }
761d8f4dcbSJay
771d8f4dcbSJay  // --------------------------------------------
781d8f4dcbSJay  // s_invalid: receive requests
791d8f4dcbSJay  when (state === s_invalid) {
801d8f4dcbSJay    io.req.ready := true.B
811d8f4dcbSJay
821d8f4dcbSJay    when (io.req.fire()) {
831d8f4dcbSJay      req   := io.req.bits
841d8f4dcbSJay      state := s_refill_req
851d8f4dcbSJay    }
861d8f4dcbSJay  }
871d8f4dcbSJay
881d8f4dcbSJay
891d8f4dcbSJay  when (state === s_refill_req) {
901d8f4dcbSJay    val address_aligned = req.addr(req.addr.getWidth - 1, log2Ceil(mmioBusBytes))
911d8f4dcbSJay    io.mmio_acquire.valid := true.B
921d8f4dcbSJay    io.mmio_acquire.bits  := edge.Get(
931d8f4dcbSJay          fromSource      = io.id,
941d8f4dcbSJay          toAddress       = Cat(address_aligned, 0.U(log2Ceil(mmioBusBytes).W)),
951d8f4dcbSJay          lgSize          = log2Ceil(mmioBusBytes).U
961d8f4dcbSJay        )._2
971d8f4dcbSJay
981d8f4dcbSJay    when (io.mmio_acquire.fire()) {
991d8f4dcbSJay      state := s_refill_resp
1001d8f4dcbSJay    }
1011d8f4dcbSJay  }
1021d8f4dcbSJay
1031d8f4dcbSJay  val (_, _, refill_done, _) = edge.addr_inc(io.mmio_grant)
1041d8f4dcbSJay
1051d8f4dcbSJay  when (state === s_refill_resp) {
1061d8f4dcbSJay    io.mmio_grant.ready := true.B
1071d8f4dcbSJay
1081d8f4dcbSJay    when (io.mmio_grant.fire()) {
1091d8f4dcbSJay      respDataReg := io.mmio_grant.bits.data
1101d8f4dcbSJay      state := s_send_resp
1111d8f4dcbSJay    }
1121d8f4dcbSJay  }
1131d8f4dcbSJay
1141d8f4dcbSJay  def getDataFromBus(pc: UInt) = {
1151d8f4dcbSJay    val respData = Wire(UInt(maxInstrLen.W))
1161d8f4dcbSJay    respData := Mux(pc(2,1) === "b00".U, respDataReg(31,0),
1171d8f4dcbSJay        Mux(pc(2,1) === "b01".U, respDataReg(47,16),
1181d8f4dcbSJay          Mux(pc(2,1) === "b10".U, respDataReg(63,32),
1191d8f4dcbSJay            Cat(0.U, respDataReg(63,48))
1201d8f4dcbSJay          )
1211d8f4dcbSJay        )
1221d8f4dcbSJay      )
1231d8f4dcbSJay    respData
1241d8f4dcbSJay  }
1251d8f4dcbSJay
1261d8f4dcbSJay  when (state === s_send_resp) {
1271d8f4dcbSJay    io.resp.valid     := !needFlush
1281d8f4dcbSJay    io.resp.bits.data :=  getDataFromBus(req.addr)
1291d8f4dcbSJay    // meta data should go with the response
1301d8f4dcbSJay    when (io.resp.fire() || needFlush) {
1311d8f4dcbSJay      state := s_invalid
1321d8f4dcbSJay    }
1331d8f4dcbSJay  }
1341d8f4dcbSJay}
1351d8f4dcbSJay
1361d8f4dcbSJayclass InstrUncacheIO(implicit p: Parameters) extends ICacheBundle {
1371d8f4dcbSJay    val req = Flipped(DecoupledIO(new InsUncacheReq ))
1381d8f4dcbSJay    val resp = DecoupledIO(new InsUncacheResp)
1391d8f4dcbSJay    val flush = Input(Bool())
1401d8f4dcbSJay}
1411d8f4dcbSJay
1421d8f4dcbSJayclass InstrUncache()(implicit p: Parameters) extends LazyModule with HasICacheParameters {
143*95e60e55STang Haojin  override def shouldBeInlined: Boolean = false
1441d8f4dcbSJay
1451d8f4dcbSJay  val clientParameters = TLMasterPortParameters.v1(
1461d8f4dcbSJay    clients = Seq(TLMasterParameters.v1(
1471d8f4dcbSJay      "InstrUncache",
1481d8f4dcbSJay      sourceId = IdRange(0, cacheParams.nMMIOs)
1491d8f4dcbSJay    ))
1501d8f4dcbSJay  )
1511d8f4dcbSJay  val clientNode = TLClientNode(Seq(clientParameters))
1521d8f4dcbSJay
1531d8f4dcbSJay  lazy val module = new InstrUncacheImp(this)
1541d8f4dcbSJay
1551d8f4dcbSJay}
1561d8f4dcbSJay
1571d8f4dcbSJayclass InstrUncacheImp(outer: InstrUncache)
1581d8f4dcbSJay  extends LazyModuleImp(outer)
1591d8f4dcbSJay    with HasICacheParameters
1601d8f4dcbSJay    with HasTLDump
1611d8f4dcbSJay{
1621d8f4dcbSJay  val io = IO(new InstrUncacheIO)
1631d8f4dcbSJay
1641d8f4dcbSJay  val (bus, edge) = outer.clientNode.out.head
1651d8f4dcbSJay
1661d8f4dcbSJay  val resp_arb = Module(new Arbiter(new InsUncacheResp, cacheParams.nMMIOs))
1671d8f4dcbSJay
1681d8f4dcbSJay  val req  = io.req
1691d8f4dcbSJay  val resp = io.resp
1701d8f4dcbSJay  val mmio_acquire = bus.a
1711d8f4dcbSJay  val mmio_grant   = bus.d
1721d8f4dcbSJay
1731d8f4dcbSJay  val entry_alloc_idx = Wire(UInt())
1741d8f4dcbSJay  val req_ready = WireInit(false.B)
1751d8f4dcbSJay
1761d8f4dcbSJay  // assign default values to output signals
1771d8f4dcbSJay  bus.b.ready := false.B
1781d8f4dcbSJay  bus.c.valid := false.B
1791d8f4dcbSJay  bus.c.bits  := DontCare
1801d8f4dcbSJay  bus.d.ready := false.B
1811d8f4dcbSJay  bus.e.valid := false.B
1821d8f4dcbSJay  bus.e.bits  := DontCare
1831d8f4dcbSJay
1841d8f4dcbSJay  val entries = (0 until cacheParams.nMMIOs) map { i =>
1851d8f4dcbSJay    val entry = Module(new InstrMMIOEntry(edge))
1861d8f4dcbSJay
1871d8f4dcbSJay    entry.io.id := i.U(log2Up(cacheParams.nMMIOs).W)
1881d8f4dcbSJay    entry.io.flush := io.flush
1891d8f4dcbSJay
1901d8f4dcbSJay    // entry req
1911d8f4dcbSJay    entry.io.req.valid := (i.U === entry_alloc_idx) && req.valid
1921d8f4dcbSJay    entry.io.req.bits  := req.bits
1931d8f4dcbSJay    when (i.U === entry_alloc_idx) {
1941d8f4dcbSJay      req_ready := entry.io.req.ready
1951d8f4dcbSJay    }
1961d8f4dcbSJay
1971d8f4dcbSJay    // entry resp
1981d8f4dcbSJay    resp_arb.io.in(i) <> entry.io.resp
1991d8f4dcbSJay
2001d8f4dcbSJay    entry.io.mmio_grant.valid := false.B
2011d8f4dcbSJay    entry.io.mmio_grant.bits  := DontCare
2021d8f4dcbSJay    when (mmio_grant.bits.source === i.U) {
2031d8f4dcbSJay      entry.io.mmio_grant <> mmio_grant
2041d8f4dcbSJay    }
2051d8f4dcbSJay    entry
2061d8f4dcbSJay  }
2071d8f4dcbSJay
2081d8f4dcbSJay  entry_alloc_idx    := PriorityEncoder(entries.map(m=>m.io.req.ready))
2091d8f4dcbSJay
2101d8f4dcbSJay  req.ready  := req_ready
2111d8f4dcbSJay  resp          <> resp_arb.io.out
2121d8f4dcbSJay  TLArbiter.lowestFromSeq(edge, mmio_acquire, entries.map(_.io.mmio_acquire))
2131d8f4dcbSJay
2141d8f4dcbSJay}
215