xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/InstrUncache.scala (revision 039cdc35f5f3b68b6295ec5ace90f22a77322e02)
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 utils._
22import utility._
23import org.chipsalliance.cde.config.Parameters
24import freechips.rocketchip.diplomacy.{IdRange, LazyModule, LazyModuleImp, TransferSizes}
25import freechips.rocketchip.tilelink.{TLArbiter, TLBundleA, TLBundleD, TLClientNode, TLEdgeOut, TLMasterParameters, TLMasterPortParameters}
26import xiangshan._
27import xiangshan.frontend._
28
29class InsUncacheReq(implicit p: Parameters) extends ICacheBundle
30{
31    val addr = UInt(PAddrBits.W)
32}
33
34class InsUncacheResp(implicit p: Parameters) extends ICacheBundle
35{
36  val data = UInt(maxInstrLen.W)
37}
38
39// One miss entry deals with one mmio request
40class InstrMMIOEntry(edge: TLEdgeOut)(implicit p: Parameters) extends XSModule with HasICacheParameters with HasIFUConst
41{
42  val io = IO(new Bundle {
43    val id = Input(UInt(log2Up(cacheParams.nMMIOs).W))
44    // client requests
45    val req = Flipped(DecoupledIO(new InsUncacheReq))
46    val resp = DecoupledIO(new InsUncacheResp)
47
48    val mmio_acquire = DecoupledIO(new TLBundleA(edge.bundle))
49    val mmio_grant   = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
50
51    val flush = Input(Bool())
52  })
53
54
55  val s_invalid :: s_refill_req :: s_refill_resp :: s_send_resp :: Nil = Enum(4)
56
57  val state = RegInit(s_invalid)
58
59  val req       = Reg(new InsUncacheReq )
60  val respDataReg = Reg(UInt(mmioBusWidth.W))
61
62  // assign default values to output signals
63  io.req.ready           := false.B
64  io.resp.valid          := false.B
65  io.resp.bits           := DontCare
66
67  io.mmio_acquire.valid   := false.B
68  io.mmio_acquire.bits    := DontCare
69
70  io.mmio_grant.ready     := false.B
71
72  val needFlush = RegInit(false.B)
73
74  when(io.flush && (state =/= s_invalid) && (state =/= s_send_resp)){ needFlush := true.B }
75  .elsewhen((state=== s_send_resp) && needFlush){ needFlush := false.B }
76
77  // --------------------------------------------
78  // s_invalid: receive requests
79  when (state === s_invalid) {
80    io.req.ready := true.B
81
82    when (io.req.fire) {
83      req   := io.req.bits
84      state := s_refill_req
85    }
86  }
87
88
89  when (state === s_refill_req) {
90    val address_aligned = req.addr(req.addr.getWidth - 1, log2Ceil(mmioBusBytes))
91    io.mmio_acquire.valid := true.B
92    io.mmio_acquire.bits  := edge.Get(
93          fromSource      = io.id,
94          toAddress       = Cat(address_aligned, 0.U(log2Ceil(mmioBusBytes).W)),
95          lgSize          = log2Ceil(mmioBusBytes).U
96        )._2
97
98    when (io.mmio_acquire.fire) {
99      state := s_refill_resp
100    }
101  }
102
103  val (_, _, refill_done, _) = edge.addr_inc(io.mmio_grant)
104
105  when (state === s_refill_resp) {
106    io.mmio_grant.ready := true.B
107
108    when (io.mmio_grant.fire) {
109      respDataReg := io.mmio_grant.bits.data
110      state := s_send_resp
111    }
112  }
113
114  def getDataFromBus(pc: UInt) = {
115    val respData = Wire(UInt(maxInstrLen.W))
116    respData := Mux(pc(2,1) === "b00".U, respDataReg(31,0),
117        Mux(pc(2,1) === "b01".U, respDataReg(47,16),
118          Mux(pc(2,1) === "b10".U, respDataReg(63,32),
119            Cat(0.U, respDataReg(63,48))
120          )
121        )
122      )
123    respData
124  }
125
126  when (state === s_send_resp) {
127    io.resp.valid     := !needFlush
128    io.resp.bits.data :=  getDataFromBus(req.addr)
129    // meta data should go with the response
130    when (io.resp.fire || needFlush) {
131      state := s_invalid
132    }
133  }
134}
135
136class InstrUncacheIO(implicit p: Parameters) extends ICacheBundle {
137    val req = Flipped(DecoupledIO(new InsUncacheReq ))
138    val resp = DecoupledIO(new InsUncacheResp)
139    val flush = Input(Bool())
140}
141
142class InstrUncache()(implicit p: Parameters) extends LazyModule with HasICacheParameters {
143  override def shouldBeInlined: Boolean = false
144
145  val clientParameters = TLMasterPortParameters.v1(
146    clients = Seq(TLMasterParameters.v1(
147      "InstrUncache",
148      sourceId = IdRange(0, cacheParams.nMMIOs)
149    ))
150  )
151  val clientNode = TLClientNode(Seq(clientParameters))
152
153  lazy val module = new InstrUncacheImp(this)
154
155}
156
157class InstrUncacheImp(outer: InstrUncache)
158  extends LazyModuleImp(outer)
159    with HasICacheParameters
160    with HasTLDump
161{
162  val io = IO(new InstrUncacheIO)
163
164  val (bus, edge) = outer.clientNode.out.head
165
166  val resp_arb = Module(new Arbiter(new InsUncacheResp, cacheParams.nMMIOs))
167
168  val req  = io.req
169  val resp = io.resp
170  val mmio_acquire = bus.a
171  val mmio_grant   = bus.d
172
173  val entry_alloc_idx = Wire(UInt())
174  val req_ready = WireInit(false.B)
175
176  // assign default values to output signals
177  bus.b.ready := false.B
178  bus.c.valid := false.B
179  bus.c.bits  := DontCare
180  bus.d.ready := false.B
181  bus.e.valid := false.B
182  bus.e.bits  := DontCare
183
184  val entries = (0 until cacheParams.nMMIOs) map { i =>
185    val entry = Module(new InstrMMIOEntry(edge))
186
187    entry.io.id := i.U(log2Up(cacheParams.nMMIOs).W)
188    entry.io.flush := io.flush
189
190    // entry req
191    entry.io.req.valid := (i.U === entry_alloc_idx) && req.valid
192    entry.io.req.bits  := req.bits
193    when (i.U === entry_alloc_idx) {
194      req_ready := entry.io.req.ready
195    }
196
197    // entry resp
198    resp_arb.io.in(i) <> entry.io.resp
199
200    entry.io.mmio_grant.valid := false.B
201    entry.io.mmio_grant.bits  := DontCare
202    when (mmio_grant.bits.source === i.U) {
203      entry.io.mmio_grant <> mmio_grant
204    }
205    entry
206  }
207
208  entry_alloc_idx    := PriorityEncoder(entries.map(m=>m.io.req.ready))
209
210  req.ready  := req_ready
211  resp          <> resp_arb.io.out
212  TLArbiter.lowestFromSeq(edge, mmio_acquire, entries.map(_.io.mmio_acquire))
213
214}
215