xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/InstrUncache.scala (revision ae3969316eb5e8c2cf8f323541ccba5fd8b22c3d)
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