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