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