xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/InstrUncache.scala (revision dfb03ba23f992cd1857e5adad219134a904431f8)
11d8f4dcbSJay/***************************************************************************************
26c106319Sxu_zh* Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC)
36c106319Sxu_zh* Copyright (c) 2020-2024 Institute of Computing Technology, Chinese Academy of Sciences
41d8f4dcbSJay* Copyright (c) 2020-2021 Peng Cheng Laboratory
51d8f4dcbSJay*
61d8f4dcbSJay* XiangShan is licensed under Mulan PSL v2.
71d8f4dcbSJay* You can use this software according to the terms and conditions of the Mulan PSL v2.
81d8f4dcbSJay* You may obtain a copy of Mulan PSL v2 at:
91d8f4dcbSJay*          http://license.coscl.org.cn/MulanPSL2
101d8f4dcbSJay*
111d8f4dcbSJay* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
121d8f4dcbSJay* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
131d8f4dcbSJay* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
141d8f4dcbSJay*
151d8f4dcbSJay* See the Mulan PSL v2 for more details.
161d8f4dcbSJay***************************************************************************************/
171d8f4dcbSJay
181d8f4dcbSJaypackage xiangshan.frontend.icache
191d8f4dcbSJay
201d8f4dcbSJayimport chisel3._
211d8f4dcbSJayimport chisel3.util._
22cf7d6b7aSMuziimport freechips.rocketchip.diplomacy.IdRange
23cf7d6b7aSMuziimport freechips.rocketchip.diplomacy.LazyModule
24cf7d6b7aSMuziimport freechips.rocketchip.diplomacy.LazyModuleImp
25cf7d6b7aSMuziimport freechips.rocketchip.tilelink.TLArbiter
26cf7d6b7aSMuziimport freechips.rocketchip.tilelink.TLBundleA
27cf7d6b7aSMuziimport freechips.rocketchip.tilelink.TLBundleD
28cf7d6b7aSMuziimport freechips.rocketchip.tilelink.TLClientNode
29cf7d6b7aSMuziimport freechips.rocketchip.tilelink.TLEdgeOut
30cf7d6b7aSMuziimport freechips.rocketchip.tilelink.TLMasterParameters
31cf7d6b7aSMuziimport freechips.rocketchip.tilelink.TLMasterPortParameters
328891a219SYinan Xuimport org.chipsalliance.cde.config.Parameters
33cf7d6b7aSMuziimport utils._
341d8f4dcbSJayimport xiangshan.frontend._
351d8f4dcbSJay
36cf7d6b7aSMuziclass InsUncacheReq(implicit p: Parameters) extends ICacheBundle {
37415fcbe2Sxu_zh  val addr: UInt = UInt(PAddrBits.W)
381d8f4dcbSJay}
391d8f4dcbSJay
40cf7d6b7aSMuziclass InsUncacheResp(implicit p: Parameters) extends ICacheBundle {
41415fcbe2Sxu_zh  val data:    UInt = UInt(maxInstrLen.W)
42*dfb03ba2Sxu_zh  val corrupt: Bool = Bool()
43415fcbe2Sxu_zh}
44415fcbe2Sxu_zh
45415fcbe2Sxu_zhclass InstrMMIOEntryIO(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheBundle {
46415fcbe2Sxu_zh  val id: UInt = Input(UInt(log2Up(cacheParams.nMMIOs).W))
47415fcbe2Sxu_zh  // client requests
48415fcbe2Sxu_zh  val req:  DecoupledIO[InsUncacheReq]  = Flipped(DecoupledIO(new InsUncacheReq))
49415fcbe2Sxu_zh  val resp: DecoupledIO[InsUncacheResp] = DecoupledIO(new InsUncacheResp)
50415fcbe2Sxu_zh
51415fcbe2Sxu_zh  val mmio_acquire: DecoupledIO[TLBundleA] = DecoupledIO(new TLBundleA(edge.bundle))
52415fcbe2Sxu_zh  val mmio_grant:   DecoupledIO[TLBundleD] = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
53415fcbe2Sxu_zh
54415fcbe2Sxu_zh  val flush: Bool = Input(Bool())
551d8f4dcbSJay}
561d8f4dcbSJay
571d8f4dcbSJay// One miss entry deals with one mmio request
58415fcbe2Sxu_zhclass InstrMMIOEntry(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheModule with HasIFUConst {
59415fcbe2Sxu_zh  val io: InstrMMIOEntryIO = IO(new InstrMMIOEntryIO(edge))
601d8f4dcbSJay
61415fcbe2Sxu_zh  private val s_invalid :: s_refill_req :: s_refill_resp :: s_send_resp :: Nil = Enum(4)
621d8f4dcbSJay
63415fcbe2Sxu_zh  private val state = RegInit(s_invalid)
641d8f4dcbSJay
65415fcbe2Sxu_zh  private val req            = Reg(new InsUncacheReq)
66*dfb03ba2Sxu_zh  private val respDataReg    = RegInit(0.U(mmioBusWidth.W))
67*dfb03ba2Sxu_zh  private val respCorruptReg = RegInit(false.B)
681d8f4dcbSJay
691d8f4dcbSJay  // assign default values to output signals
701d8f4dcbSJay  io.req.ready  := false.B
711d8f4dcbSJay  io.resp.valid := false.B
721d8f4dcbSJay  io.resp.bits  := DontCare
731d8f4dcbSJay
741d8f4dcbSJay  io.mmio_acquire.valid := false.B
751d8f4dcbSJay  io.mmio_acquire.bits  := DontCare
761d8f4dcbSJay
771d8f4dcbSJay  io.mmio_grant.ready := false.B
781d8f4dcbSJay
79415fcbe2Sxu_zh  private val needFlush = RegInit(false.B)
801d8f4dcbSJay
81cf7d6b7aSMuzi  when(io.flush && (state =/= s_invalid) && (state =/= s_send_resp))(needFlush := true.B)
82cf7d6b7aSMuzi    .elsewhen((state === s_send_resp) && needFlush)(needFlush := false.B)
831d8f4dcbSJay
841d8f4dcbSJay  // --------------------------------------------
851d8f4dcbSJay  // s_invalid: receive requests
861d8f4dcbSJay  when(state === s_invalid) {
871d8f4dcbSJay    io.req.ready := true.B
881d8f4dcbSJay
89935edac4STang Haojin    when(io.req.fire) {
901d8f4dcbSJay      req   := io.req.bits
911d8f4dcbSJay      state := s_refill_req
921d8f4dcbSJay    }
931d8f4dcbSJay  }
941d8f4dcbSJay
951d8f4dcbSJay  when(state === s_refill_req) {
961d8f4dcbSJay    val address_aligned = req.addr(req.addr.getWidth - 1, log2Ceil(mmioBusBytes))
971d8f4dcbSJay    io.mmio_acquire.valid := true.B
981d8f4dcbSJay    io.mmio_acquire.bits := edge.Get(
991d8f4dcbSJay      fromSource = io.id,
1001d8f4dcbSJay      toAddress = Cat(address_aligned, 0.U(log2Ceil(mmioBusBytes).W)),
1011d8f4dcbSJay      lgSize = log2Ceil(mmioBusBytes).U
1021d8f4dcbSJay    )._2
1031d8f4dcbSJay
104935edac4STang Haojin    when(io.mmio_acquire.fire) {
1051d8f4dcbSJay      state := s_refill_resp
1061d8f4dcbSJay    }
1071d8f4dcbSJay  }
1081d8f4dcbSJay
1091d8f4dcbSJay  val (_, _, refill_done, _) = edge.addr_inc(io.mmio_grant)
1101d8f4dcbSJay
1111d8f4dcbSJay  when(state === s_refill_resp) {
1121d8f4dcbSJay    io.mmio_grant.ready := true.B
1131d8f4dcbSJay
114935edac4STang Haojin    when(io.mmio_grant.fire) {
1151d8f4dcbSJay      respDataReg    := io.mmio_grant.bits.data
116*dfb03ba2Sxu_zh      respCorruptReg := io.mmio_grant.bits.corrupt // this includes bits.denied, as tilelink spec defines
1171d8f4dcbSJay      state          := s_send_resp
1181d8f4dcbSJay    }
1191d8f4dcbSJay  }
1201d8f4dcbSJay
121415fcbe2Sxu_zh  private def getDataFromBus(pc: UInt): UInt = {
1221d8f4dcbSJay    val respData = Wire(UInt(maxInstrLen.W))
123cf7d6b7aSMuzi    respData := Mux(
124cf7d6b7aSMuzi      pc(2, 1) === "b00".U,
125cf7d6b7aSMuzi      respDataReg(31, 0),
126cf7d6b7aSMuzi      Mux(
127cf7d6b7aSMuzi        pc(2, 1) === "b01".U,
128cf7d6b7aSMuzi        respDataReg(47, 16),
129cf7d6b7aSMuzi        Mux(pc(2, 1) === "b10".U, respDataReg(63, 32), Cat(0.U, respDataReg(63, 48)))
1301d8f4dcbSJay      )
1311d8f4dcbSJay    )
1321d8f4dcbSJay    respData
1331d8f4dcbSJay  }
1341d8f4dcbSJay
1351d8f4dcbSJay  when(state === s_send_resp) {
1361d8f4dcbSJay    io.resp.valid        := !needFlush
1371d8f4dcbSJay    io.resp.bits.data    := getDataFromBus(req.addr)
138*dfb03ba2Sxu_zh    io.resp.bits.corrupt := respCorruptReg
1391d8f4dcbSJay    // metadata should go with the response
140935edac4STang Haojin    when(io.resp.fire || needFlush) {
1411d8f4dcbSJay      state := s_invalid
1421d8f4dcbSJay    }
1431d8f4dcbSJay  }
1441d8f4dcbSJay}
1451d8f4dcbSJay
1461d8f4dcbSJayclass InstrUncacheIO(implicit p: Parameters) extends ICacheBundle {
147415fcbe2Sxu_zh  val req:   DecoupledIO[InsUncacheReq]  = Flipped(DecoupledIO(new InsUncacheReq))
148415fcbe2Sxu_zh  val resp:  DecoupledIO[InsUncacheResp] = DecoupledIO(new InsUncacheResp)
149415fcbe2Sxu_zh  val flush: Bool                        = Input(Bool())
1501d8f4dcbSJay}
1511d8f4dcbSJay
1521d8f4dcbSJayclass InstrUncache()(implicit p: Parameters) extends LazyModule with HasICacheParameters {
15395e60e55STang Haojin  override def shouldBeInlined: Boolean = false
1541d8f4dcbSJay
155415fcbe2Sxu_zh  val clientParameters: TLMasterPortParameters = TLMasterPortParameters.v1(
1561d8f4dcbSJay    clients = Seq(TLMasterParameters.v1(
1571d8f4dcbSJay      "InstrUncache",
1581d8f4dcbSJay      sourceId = IdRange(0, cacheParams.nMMIOs)
1591d8f4dcbSJay    ))
1601d8f4dcbSJay  )
161415fcbe2Sxu_zh  val clientNode: TLClientNode = TLClientNode(Seq(clientParameters))
1621d8f4dcbSJay
163415fcbe2Sxu_zh  lazy val module: InstrUncacheImp = new InstrUncacheImp(this)
1641d8f4dcbSJay}
1651d8f4dcbSJay
1661d8f4dcbSJayclass InstrUncacheImp(outer: InstrUncache)
1671d8f4dcbSJay    extends LazyModuleImp(outer)
1681d8f4dcbSJay    with HasICacheParameters
169cf7d6b7aSMuzi    with HasTLDump {
170415fcbe2Sxu_zh  val io: InstrUncacheIO = IO(new InstrUncacheIO)
1711d8f4dcbSJay
172415fcbe2Sxu_zh  private val (bus, edge) = outer.clientNode.out.head
1731d8f4dcbSJay
174415fcbe2Sxu_zh  private val resp_arb = Module(new Arbiter(new InsUncacheResp, cacheParams.nMMIOs))
1751d8f4dcbSJay
176415fcbe2Sxu_zh  private val req          = io.req
177415fcbe2Sxu_zh  private val resp         = io.resp
178415fcbe2Sxu_zh  private val mmio_acquire = bus.a
179415fcbe2Sxu_zh  private val mmio_grant   = bus.d
1801d8f4dcbSJay
181415fcbe2Sxu_zh  private val entry_alloc_idx = Wire(UInt())
182415fcbe2Sxu_zh  private val req_ready       = WireInit(false.B)
1831d8f4dcbSJay
1841d8f4dcbSJay  // assign default values to output signals
1851d8f4dcbSJay  bus.b.ready := false.B
1861d8f4dcbSJay  bus.c.valid := false.B
1871d8f4dcbSJay  bus.c.bits  := DontCare
1881d8f4dcbSJay  bus.d.ready := false.B
1891d8f4dcbSJay  bus.e.valid := false.B
1901d8f4dcbSJay  bus.e.bits  := DontCare
1911d8f4dcbSJay
192415fcbe2Sxu_zh  private val entries = (0 until cacheParams.nMMIOs).map { i =>
1931d8f4dcbSJay    val entry = Module(new InstrMMIOEntry(edge))
1941d8f4dcbSJay
1951d8f4dcbSJay    entry.io.id    := i.U(log2Up(cacheParams.nMMIOs).W)
1961d8f4dcbSJay    entry.io.flush := io.flush
1971d8f4dcbSJay
1981d8f4dcbSJay    // entry req
1991d8f4dcbSJay    entry.io.req.valid := (i.U === entry_alloc_idx) && req.valid
2001d8f4dcbSJay    entry.io.req.bits  := req.bits
2011d8f4dcbSJay    when(i.U === entry_alloc_idx) {
2021d8f4dcbSJay      req_ready := entry.io.req.ready
2031d8f4dcbSJay    }
2041d8f4dcbSJay
2051d8f4dcbSJay    // entry resp
2061d8f4dcbSJay    resp_arb.io.in(i) <> entry.io.resp
2071d8f4dcbSJay
2081d8f4dcbSJay    entry.io.mmio_grant.valid := false.B
2091d8f4dcbSJay    entry.io.mmio_grant.bits  := DontCare
2101d8f4dcbSJay    when(mmio_grant.bits.source === i.U) {
2111d8f4dcbSJay      entry.io.mmio_grant <> mmio_grant
2121d8f4dcbSJay    }
2131d8f4dcbSJay    entry
2141d8f4dcbSJay  }
2151d8f4dcbSJay
216*dfb03ba2Sxu_zh  // override mmio_grant.ready to prevent x-propagation
217*dfb03ba2Sxu_zh  mmio_grant.ready := true.B
218*dfb03ba2Sxu_zh
2191d8f4dcbSJay  entry_alloc_idx := PriorityEncoder(entries.map(m => m.io.req.ready))
2201d8f4dcbSJay
2211d8f4dcbSJay  req.ready := req_ready
2221d8f4dcbSJay  resp <> resp_arb.io.out
2231d8f4dcbSJay  TLArbiter.lowestFromSeq(edge, mmio_acquire, entries.map(_.io.mmio_acquire))
2241d8f4dcbSJay}
225