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