xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/InstrUncache.scala (revision 1d8f4dcb81f46f3830f09013a9836143401cc425)
1*1d8f4dcbSJay/***************************************************************************************
2*1d8f4dcbSJay* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3*1d8f4dcbSJay* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*1d8f4dcbSJay*
5*1d8f4dcbSJay* XiangShan is licensed under Mulan PSL v2.
6*1d8f4dcbSJay* You can use this software according to the terms and conditions of the Mulan PSL v2.
7*1d8f4dcbSJay* You may obtain a copy of Mulan PSL v2 at:
8*1d8f4dcbSJay*          http://license.coscl.org.cn/MulanPSL2
9*1d8f4dcbSJay*
10*1d8f4dcbSJay* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11*1d8f4dcbSJay* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12*1d8f4dcbSJay* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*1d8f4dcbSJay*
14*1d8f4dcbSJay* See the Mulan PSL v2 for more details.
15*1d8f4dcbSJay***************************************************************************************/
16*1d8f4dcbSJay
17*1d8f4dcbSJaypackage xiangshan.frontend.icache
18*1d8f4dcbSJay
19*1d8f4dcbSJayimport chisel3._
20*1d8f4dcbSJayimport chisel3.util._
21*1d8f4dcbSJayimport utils._
22*1d8f4dcbSJayimport chipsalliance.rocketchip.config.Parameters
23*1d8f4dcbSJayimport freechips.rocketchip.diplomacy.{IdRange, LazyModule, LazyModuleImp, TransferSizes}
24*1d8f4dcbSJayimport freechips.rocketchip.tilelink.{TLArbiter, TLBundleA, TLBundleD, TLClientNode, TLEdgeOut, TLMasterParameters, TLMasterPortParameters}
25*1d8f4dcbSJayimport xiangshan._
26*1d8f4dcbSJayimport xiangshan.frontend._
27*1d8f4dcbSJay
28*1d8f4dcbSJayclass InsUncacheReq(implicit p: Parameters) extends ICacheBundle
29*1d8f4dcbSJay{
30*1d8f4dcbSJay    val addr = UInt(PAddrBits.W)
31*1d8f4dcbSJay}
32*1d8f4dcbSJay
33*1d8f4dcbSJayclass InsUncacheResp(implicit p: Parameters) extends ICacheBundle
34*1d8f4dcbSJay{
35*1d8f4dcbSJay  val data = UInt(maxInstrLen.W)
36*1d8f4dcbSJay}
37*1d8f4dcbSJay
38*1d8f4dcbSJay// One miss entry deals with one mmio request
39*1d8f4dcbSJayclass InstrMMIOEntry(edge: TLEdgeOut)(implicit p: Parameters) extends XSModule with HasICacheParameters with HasIFUConst
40*1d8f4dcbSJay{
41*1d8f4dcbSJay  val io = IO(new Bundle {
42*1d8f4dcbSJay    val id = Input(UInt(log2Up(cacheParams.nMMIOs).W))
43*1d8f4dcbSJay    // client requests
44*1d8f4dcbSJay    val req = Flipped(DecoupledIO(new InsUncacheReq))
45*1d8f4dcbSJay    val resp = DecoupledIO(new InsUncacheResp)
46*1d8f4dcbSJay
47*1d8f4dcbSJay    val mmio_acquire = DecoupledIO(new TLBundleA(edge.bundle))
48*1d8f4dcbSJay    val mmio_grant   = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
49*1d8f4dcbSJay
50*1d8f4dcbSJay    val flush = Input(Bool())
51*1d8f4dcbSJay  })
52*1d8f4dcbSJay
53*1d8f4dcbSJay
54*1d8f4dcbSJay  val s_invalid :: s_refill_req :: s_refill_resp :: s_send_resp :: Nil = Enum(4)
55*1d8f4dcbSJay
56*1d8f4dcbSJay  val state = RegInit(s_invalid)
57*1d8f4dcbSJay
58*1d8f4dcbSJay  val req       = Reg(new InsUncacheReq )
59*1d8f4dcbSJay  val respDataReg = Reg(UInt(mmioBusWidth.W))
60*1d8f4dcbSJay
61*1d8f4dcbSJay  // assign default values to output signals
62*1d8f4dcbSJay  io.req.ready           := false.B
63*1d8f4dcbSJay  io.resp.valid          := false.B
64*1d8f4dcbSJay  io.resp.bits           := DontCare
65*1d8f4dcbSJay
66*1d8f4dcbSJay  io.mmio_acquire.valid   := false.B
67*1d8f4dcbSJay  io.mmio_acquire.bits    := DontCare
68*1d8f4dcbSJay
69*1d8f4dcbSJay  io.mmio_grant.ready     := false.B
70*1d8f4dcbSJay
71*1d8f4dcbSJay  val needFlush = RegInit(false.B)
72*1d8f4dcbSJay
73*1d8f4dcbSJay  when(io.flush && (state =/= s_invalid) && (state =/= s_send_resp)){ needFlush := true.B }
74*1d8f4dcbSJay  .elsewhen((state=== s_send_resp) && needFlush){ needFlush := false.B }
75*1d8f4dcbSJay
76*1d8f4dcbSJay  // --------------------------------------------
77*1d8f4dcbSJay  // s_invalid: receive requests
78*1d8f4dcbSJay  when (state === s_invalid) {
79*1d8f4dcbSJay    io.req.ready := true.B
80*1d8f4dcbSJay
81*1d8f4dcbSJay    when (io.req.fire()) {
82*1d8f4dcbSJay      req   := io.req.bits
83*1d8f4dcbSJay      state := s_refill_req
84*1d8f4dcbSJay    }
85*1d8f4dcbSJay  }
86*1d8f4dcbSJay
87*1d8f4dcbSJay
88*1d8f4dcbSJay  when (state === s_refill_req) {
89*1d8f4dcbSJay    val address_aligned = req.addr(req.addr.getWidth - 1, log2Ceil(mmioBusBytes))
90*1d8f4dcbSJay    io.mmio_acquire.valid := true.B
91*1d8f4dcbSJay    io.mmio_acquire.bits  := edge.Get(
92*1d8f4dcbSJay          fromSource      = io.id,
93*1d8f4dcbSJay          toAddress       = Cat(address_aligned, 0.U(log2Ceil(mmioBusBytes).W)),
94*1d8f4dcbSJay          lgSize          = log2Ceil(mmioBusBytes).U
95*1d8f4dcbSJay        )._2
96*1d8f4dcbSJay
97*1d8f4dcbSJay    when (io.mmio_acquire.fire()) {
98*1d8f4dcbSJay      state := s_refill_resp
99*1d8f4dcbSJay    }
100*1d8f4dcbSJay  }
101*1d8f4dcbSJay
102*1d8f4dcbSJay  val (_, _, refill_done, _) = edge.addr_inc(io.mmio_grant)
103*1d8f4dcbSJay
104*1d8f4dcbSJay  when (state === s_refill_resp) {
105*1d8f4dcbSJay    io.mmio_grant.ready := true.B
106*1d8f4dcbSJay
107*1d8f4dcbSJay    when (io.mmio_grant.fire()) {
108*1d8f4dcbSJay      respDataReg := io.mmio_grant.bits.data
109*1d8f4dcbSJay      state := s_send_resp
110*1d8f4dcbSJay    }
111*1d8f4dcbSJay  }
112*1d8f4dcbSJay
113*1d8f4dcbSJay  def getDataFromBus(pc: UInt) = {
114*1d8f4dcbSJay    val respData = Wire(UInt(maxInstrLen.W))
115*1d8f4dcbSJay    respData := Mux(pc(2,1) === "b00".U, respDataReg(31,0),
116*1d8f4dcbSJay        Mux(pc(2,1) === "b01".U, respDataReg(47,16),
117*1d8f4dcbSJay          Mux(pc(2,1) === "b10".U, respDataReg(63,32),
118*1d8f4dcbSJay            Cat(0.U, respDataReg(63,48))
119*1d8f4dcbSJay          )
120*1d8f4dcbSJay        )
121*1d8f4dcbSJay      )
122*1d8f4dcbSJay    respData
123*1d8f4dcbSJay  }
124*1d8f4dcbSJay
125*1d8f4dcbSJay  when (state === s_send_resp) {
126*1d8f4dcbSJay    io.resp.valid     := !needFlush
127*1d8f4dcbSJay    io.resp.bits.data :=  getDataFromBus(req.addr)
128*1d8f4dcbSJay    // meta data should go with the response
129*1d8f4dcbSJay    when (io.resp.fire() || needFlush) {
130*1d8f4dcbSJay      state := s_invalid
131*1d8f4dcbSJay    }
132*1d8f4dcbSJay  }
133*1d8f4dcbSJay}
134*1d8f4dcbSJay
135*1d8f4dcbSJayclass InstrUncacheIO(implicit p: Parameters) extends ICacheBundle {
136*1d8f4dcbSJay    val req = Flipped(DecoupledIO(new InsUncacheReq ))
137*1d8f4dcbSJay    val resp = DecoupledIO(new InsUncacheResp)
138*1d8f4dcbSJay    val flush = Input(Bool())
139*1d8f4dcbSJay}
140*1d8f4dcbSJay
141*1d8f4dcbSJayclass InstrUncache()(implicit p: Parameters) extends LazyModule with HasICacheParameters {
142*1d8f4dcbSJay
143*1d8f4dcbSJay  val clientParameters = TLMasterPortParameters.v1(
144*1d8f4dcbSJay    clients = Seq(TLMasterParameters.v1(
145*1d8f4dcbSJay      "InstrUncache",
146*1d8f4dcbSJay      sourceId = IdRange(0, cacheParams.nMMIOs)
147*1d8f4dcbSJay    ))
148*1d8f4dcbSJay  )
149*1d8f4dcbSJay  val clientNode = TLClientNode(Seq(clientParameters))
150*1d8f4dcbSJay
151*1d8f4dcbSJay  lazy val module = new InstrUncacheImp(this)
152*1d8f4dcbSJay
153*1d8f4dcbSJay}
154*1d8f4dcbSJay
155*1d8f4dcbSJayclass InstrUncacheImp(outer: InstrUncache)
156*1d8f4dcbSJay  extends LazyModuleImp(outer)
157*1d8f4dcbSJay    with HasICacheParameters
158*1d8f4dcbSJay    with HasTLDump
159*1d8f4dcbSJay{
160*1d8f4dcbSJay  val io = IO(new InstrUncacheIO)
161*1d8f4dcbSJay
162*1d8f4dcbSJay  val (bus, edge) = outer.clientNode.out.head
163*1d8f4dcbSJay
164*1d8f4dcbSJay  val resp_arb = Module(new Arbiter(new InsUncacheResp, cacheParams.nMMIOs))
165*1d8f4dcbSJay
166*1d8f4dcbSJay  val req  = io.req
167*1d8f4dcbSJay  val resp = io.resp
168*1d8f4dcbSJay  val mmio_acquire = bus.a
169*1d8f4dcbSJay  val mmio_grant   = bus.d
170*1d8f4dcbSJay
171*1d8f4dcbSJay  val entry_alloc_idx = Wire(UInt())
172*1d8f4dcbSJay  val req_ready = WireInit(false.B)
173*1d8f4dcbSJay
174*1d8f4dcbSJay  // assign default values to output signals
175*1d8f4dcbSJay  bus.b.ready := false.B
176*1d8f4dcbSJay  bus.c.valid := false.B
177*1d8f4dcbSJay  bus.c.bits  := DontCare
178*1d8f4dcbSJay  bus.d.ready := false.B
179*1d8f4dcbSJay  bus.e.valid := false.B
180*1d8f4dcbSJay  bus.e.bits  := DontCare
181*1d8f4dcbSJay
182*1d8f4dcbSJay  val entries = (0 until cacheParams.nMMIOs) map { i =>
183*1d8f4dcbSJay    val entry = Module(new InstrMMIOEntry(edge))
184*1d8f4dcbSJay
185*1d8f4dcbSJay    entry.io.id := i.U(log2Up(cacheParams.nMMIOs).W)
186*1d8f4dcbSJay    entry.io.flush := io.flush
187*1d8f4dcbSJay
188*1d8f4dcbSJay    // entry req
189*1d8f4dcbSJay    entry.io.req.valid := (i.U === entry_alloc_idx) && req.valid
190*1d8f4dcbSJay    entry.io.req.bits  := req.bits
191*1d8f4dcbSJay    when (i.U === entry_alloc_idx) {
192*1d8f4dcbSJay      req_ready := entry.io.req.ready
193*1d8f4dcbSJay    }
194*1d8f4dcbSJay
195*1d8f4dcbSJay    // entry resp
196*1d8f4dcbSJay    resp_arb.io.in(i) <> entry.io.resp
197*1d8f4dcbSJay
198*1d8f4dcbSJay    entry.io.mmio_grant.valid := false.B
199*1d8f4dcbSJay    entry.io.mmio_grant.bits  := DontCare
200*1d8f4dcbSJay    when (mmio_grant.bits.source === i.U) {
201*1d8f4dcbSJay      entry.io.mmio_grant <> mmio_grant
202*1d8f4dcbSJay    }
203*1d8f4dcbSJay    entry
204*1d8f4dcbSJay  }
205*1d8f4dcbSJay
206*1d8f4dcbSJay  entry_alloc_idx    := PriorityEncoder(entries.map(m=>m.io.req.ready))
207*1d8f4dcbSJay
208*1d8f4dcbSJay  req.ready  := req_ready
209*1d8f4dcbSJay  resp          <> resp_arb.io.out
210*1d8f4dcbSJay  TLArbiter.lowestFromSeq(edge, mmio_acquire, entries.map(_.io.mmio_acquire))
211*1d8f4dcbSJay
212*1d8f4dcbSJay}
213