xref: /XiangShan/src/main/scala/xiangshan/cache/dcache/Uncache.scala (revision 1f0e2dc71212fc9500d02db34c3c9a18760a046b)
1*1f0e2dc7SJiawei Lin/***************************************************************************************
2*1f0e2dc7SJiawei Lin* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3*1f0e2dc7SJiawei Lin* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*1f0e2dc7SJiawei Lin*
5*1f0e2dc7SJiawei Lin* XiangShan is licensed under Mulan PSL v2.
6*1f0e2dc7SJiawei Lin* You can use this software according to the terms and conditions of the Mulan PSL v2.
7*1f0e2dc7SJiawei Lin* You may obtain a copy of Mulan PSL v2 at:
8*1f0e2dc7SJiawei Lin*          http://license.coscl.org.cn/MulanPSL2
9*1f0e2dc7SJiawei Lin*
10*1f0e2dc7SJiawei Lin* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11*1f0e2dc7SJiawei Lin* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12*1f0e2dc7SJiawei Lin* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*1f0e2dc7SJiawei Lin*
14*1f0e2dc7SJiawei Lin* See the Mulan PSL v2 for more details.
15*1f0e2dc7SJiawei Lin***************************************************************************************/
16*1f0e2dc7SJiawei Lin
17*1f0e2dc7SJiawei Linpackage xiangshan.cache
18*1f0e2dc7SJiawei Lin
19*1f0e2dc7SJiawei Linimport chisel3._
20*1f0e2dc7SJiawei Linimport chisel3.util._
21*1f0e2dc7SJiawei Linimport utils.{HasTLDump, PriorityMuxWithFlag, XSDebug}
22*1f0e2dc7SJiawei Linimport chipsalliance.rocketchip.config.Parameters
23*1f0e2dc7SJiawei Linimport freechips.rocketchip.diplomacy.{IdRange, LazyModule, LazyModuleImp, TransferSizes}
24*1f0e2dc7SJiawei Linimport freechips.rocketchip.tilelink.{TLArbiter, TLBundleA, TLBundleD, TLClientNode, TLEdgeOut, TLMasterParameters, TLMasterPortParameters}
25*1f0e2dc7SJiawei Linimport xiangshan.{MicroOp, Redirect}
26*1f0e2dc7SJiawei Lin
27*1f0e2dc7SJiawei Lin// One miss entry deals with one mmio request
28*1f0e2dc7SJiawei Linclass MMIOEntry(edge: TLEdgeOut)(implicit p: Parameters) extends DCacheModule
29*1f0e2dc7SJiawei Lin{
30*1f0e2dc7SJiawei Lin  val io = IO(new Bundle {
31*1f0e2dc7SJiawei Lin    // MSHR ID
32*1f0e2dc7SJiawei Lin    val id = Input(UInt())
33*1f0e2dc7SJiawei Lin
34*1f0e2dc7SJiawei Lin    // client requests
35*1f0e2dc7SJiawei Lin    val req = Flipped(DecoupledIO(new DCacheWordReq ))
36*1f0e2dc7SJiawei Lin    val resp = DecoupledIO(new DCacheWordResp)
37*1f0e2dc7SJiawei Lin
38*1f0e2dc7SJiawei Lin    val mem_acquire = DecoupledIO(new TLBundleA(edge.bundle))
39*1f0e2dc7SJiawei Lin    val mem_grant   = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
40*1f0e2dc7SJiawei Lin  })
41*1f0e2dc7SJiawei Lin
42*1f0e2dc7SJiawei Lin
43*1f0e2dc7SJiawei Lin  val s_invalid :: s_refill_req :: s_refill_resp :: s_send_resp :: Nil = Enum(4)
44*1f0e2dc7SJiawei Lin
45*1f0e2dc7SJiawei Lin  val state = RegInit(s_invalid)
46*1f0e2dc7SJiawei Lin
47*1f0e2dc7SJiawei Lin  val req       = Reg(new DCacheWordReq )
48*1f0e2dc7SJiawei Lin  val resp_data = Reg(UInt(DataBits.W))
49*1f0e2dc7SJiawei Lin
50*1f0e2dc7SJiawei Lin
51*1f0e2dc7SJiawei Lin  // assign default values to output signals
52*1f0e2dc7SJiawei Lin  io.req.ready           := false.B
53*1f0e2dc7SJiawei Lin  io.resp.valid          := false.B
54*1f0e2dc7SJiawei Lin  io.resp.bits           := DontCare
55*1f0e2dc7SJiawei Lin
56*1f0e2dc7SJiawei Lin  io.mem_acquire.valid   := false.B
57*1f0e2dc7SJiawei Lin  io.mem_acquire.bits    := DontCare
58*1f0e2dc7SJiawei Lin
59*1f0e2dc7SJiawei Lin  io.mem_grant.ready     := false.B
60*1f0e2dc7SJiawei Lin
61*1f0e2dc7SJiawei Lin
62*1f0e2dc7SJiawei Lin  XSDebug("entry: %d state: %d\n", io.id, state)
63*1f0e2dc7SJiawei Lin  // --------------------------------------------
64*1f0e2dc7SJiawei Lin  // s_invalid: receive requests
65*1f0e2dc7SJiawei Lin  when (state === s_invalid) {
66*1f0e2dc7SJiawei Lin    io.req.ready := true.B
67*1f0e2dc7SJiawei Lin
68*1f0e2dc7SJiawei Lin    when (io.req.fire()) {
69*1f0e2dc7SJiawei Lin      req   := io.req.bits
70*1f0e2dc7SJiawei Lin      req.addr := io.req.bits.addr
71*1f0e2dc7SJiawei Lin      state := s_refill_req
72*1f0e2dc7SJiawei Lin    }
73*1f0e2dc7SJiawei Lin  }
74*1f0e2dc7SJiawei Lin
75*1f0e2dc7SJiawei Lin  // --------------------------------------------
76*1f0e2dc7SJiawei Lin  // refill
77*1f0e2dc7SJiawei Lin  // TODO: determine 'lgSize' in memend
78*1f0e2dc7SJiawei Lin  val size = PopCount(req.mask)
79*1f0e2dc7SJiawei Lin  val (lgSize, legal) = PriorityMuxWithFlag(Seq(
80*1f0e2dc7SJiawei Lin    1.U -> 0.U,
81*1f0e2dc7SJiawei Lin    2.U -> 1.U,
82*1f0e2dc7SJiawei Lin    4.U -> 2.U,
83*1f0e2dc7SJiawei Lin    8.U -> 3.U
84*1f0e2dc7SJiawei Lin  ).map(m => (size===m._1) -> m._2))
85*1f0e2dc7SJiawei Lin  assert(!(io.mem_acquire.valid && !legal))
86*1f0e2dc7SJiawei Lin
87*1f0e2dc7SJiawei Lin  val load = edge.Get(
88*1f0e2dc7SJiawei Lin    fromSource      = io.id,
89*1f0e2dc7SJiawei Lin    toAddress       = req.addr,
90*1f0e2dc7SJiawei Lin    lgSize          = lgSize
91*1f0e2dc7SJiawei Lin  )._2
92*1f0e2dc7SJiawei Lin
93*1f0e2dc7SJiawei Lin  val store = edge.Put(
94*1f0e2dc7SJiawei Lin    fromSource      = io.id,
95*1f0e2dc7SJiawei Lin    toAddress = req.addr,
96*1f0e2dc7SJiawei Lin    lgSize  = lgSize,
97*1f0e2dc7SJiawei Lin    data  = req.data,
98*1f0e2dc7SJiawei Lin    mask = req.mask
99*1f0e2dc7SJiawei Lin  )._2
100*1f0e2dc7SJiawei Lin
101*1f0e2dc7SJiawei Lin  when (state === s_refill_req) {
102*1f0e2dc7SJiawei Lin    io.mem_acquire.valid := true.B
103*1f0e2dc7SJiawei Lin    io.mem_acquire.bits  := Mux(req.cmd === MemoryOpConstants.M_XWR, store, load)
104*1f0e2dc7SJiawei Lin
105*1f0e2dc7SJiawei Lin    when (io.mem_acquire.fire()) {
106*1f0e2dc7SJiawei Lin      state := s_refill_resp
107*1f0e2dc7SJiawei Lin    }
108*1f0e2dc7SJiawei Lin  }
109*1f0e2dc7SJiawei Lin
110*1f0e2dc7SJiawei Lin  val (_, _, refill_done, _) = edge.addr_inc(io.mem_grant)
111*1f0e2dc7SJiawei Lin
112*1f0e2dc7SJiawei Lin  when (state === s_refill_resp) {
113*1f0e2dc7SJiawei Lin    io.mem_grant.ready := true.B
114*1f0e2dc7SJiawei Lin
115*1f0e2dc7SJiawei Lin    when (io.mem_grant.fire()) {
116*1f0e2dc7SJiawei Lin      resp_data := io.mem_grant.bits.data
117*1f0e2dc7SJiawei Lin      assert(refill_done, "MMIO response should be one beat only!")
118*1f0e2dc7SJiawei Lin      state := s_send_resp
119*1f0e2dc7SJiawei Lin    }
120*1f0e2dc7SJiawei Lin  }
121*1f0e2dc7SJiawei Lin
122*1f0e2dc7SJiawei Lin  // --------------------------------------------
123*1f0e2dc7SJiawei Lin  when (state === s_send_resp) {
124*1f0e2dc7SJiawei Lin    io.resp.valid := true.B
125*1f0e2dc7SJiawei Lin    io.resp.bits.data   := resp_data
126*1f0e2dc7SJiawei Lin    // meta data should go with the response
127*1f0e2dc7SJiawei Lin    io.resp.bits.id     := req.id
128*1f0e2dc7SJiawei Lin    io.resp.bits.miss   := false.B
129*1f0e2dc7SJiawei Lin    io.resp.bits.replay := false.B
130*1f0e2dc7SJiawei Lin
131*1f0e2dc7SJiawei Lin    when (io.resp.fire()) {
132*1f0e2dc7SJiawei Lin      state := s_invalid
133*1f0e2dc7SJiawei Lin    }
134*1f0e2dc7SJiawei Lin  }
135*1f0e2dc7SJiawei Lin}
136*1f0e2dc7SJiawei Lin
137*1f0e2dc7SJiawei Linclass UncacheIO(implicit p: Parameters) extends DCacheBundle {
138*1f0e2dc7SJiawei Lin  val lsq = Flipped(new DCacheWordIO)
139*1f0e2dc7SJiawei Lin}
140*1f0e2dc7SJiawei Lin
141*1f0e2dc7SJiawei Lin// convert DCacheIO to TileLink
142*1f0e2dc7SJiawei Lin// for Now, we only deal with TL-UL
143*1f0e2dc7SJiawei Lin
144*1f0e2dc7SJiawei Linclass Uncache()(implicit p: Parameters) extends LazyModule with HasDCacheParameters {
145*1f0e2dc7SJiawei Lin
146*1f0e2dc7SJiawei Lin  val clientParameters = TLMasterPortParameters.v1(
147*1f0e2dc7SJiawei Lin    clients = Seq(TLMasterParameters.v1(
148*1f0e2dc7SJiawei Lin      "uncache",
149*1f0e2dc7SJiawei Lin      sourceId = IdRange(0, cfg.nMMIOEntries)
150*1f0e2dc7SJiawei Lin    ))
151*1f0e2dc7SJiawei Lin  )
152*1f0e2dc7SJiawei Lin  val clientNode = TLClientNode(Seq(clientParameters))
153*1f0e2dc7SJiawei Lin
154*1f0e2dc7SJiawei Lin  lazy val module = new UncacheImp(this)
155*1f0e2dc7SJiawei Lin
156*1f0e2dc7SJiawei Lin}
157*1f0e2dc7SJiawei Lin
158*1f0e2dc7SJiawei Linclass UncacheImp(outer: Uncache)
159*1f0e2dc7SJiawei Lin  extends LazyModuleImp(outer)
160*1f0e2dc7SJiawei Lin    with HasDCacheParameters
161*1f0e2dc7SJiawei Lin    with HasTLDump
162*1f0e2dc7SJiawei Lin{
163*1f0e2dc7SJiawei Lin  val io = IO(new UncacheIO)
164*1f0e2dc7SJiawei Lin
165*1f0e2dc7SJiawei Lin  val (bus, edge) = outer.clientNode.out.head
166*1f0e2dc7SJiawei Lin  require(bus.d.bits.data.getWidth == wordBits, "Uncache: tilelink width does not match")
167*1f0e2dc7SJiawei Lin
168*1f0e2dc7SJiawei Lin  val resp_arb = Module(new Arbiter(new DCacheWordResp, cfg.nMMIOEntries))
169*1f0e2dc7SJiawei Lin
170*1f0e2dc7SJiawei Lin  val req  = io.lsq.req
171*1f0e2dc7SJiawei Lin  val resp = io.lsq.resp
172*1f0e2dc7SJiawei Lin  val mem_acquire = bus.a
173*1f0e2dc7SJiawei Lin  val mem_grant   = bus.d
174*1f0e2dc7SJiawei Lin
175*1f0e2dc7SJiawei Lin  val entry_alloc_idx = Wire(UInt())
176*1f0e2dc7SJiawei Lin  val req_ready = WireInit(false.B)
177*1f0e2dc7SJiawei Lin
178*1f0e2dc7SJiawei Lin  // assign default values to output signals
179*1f0e2dc7SJiawei Lin  bus.b.ready := false.B
180*1f0e2dc7SJiawei Lin  bus.c.valid := false.B
181*1f0e2dc7SJiawei Lin  bus.c.bits  := DontCare
182*1f0e2dc7SJiawei Lin  bus.d.ready := false.B
183*1f0e2dc7SJiawei Lin  bus.e.valid := false.B
184*1f0e2dc7SJiawei Lin  bus.e.bits  := DontCare
185*1f0e2dc7SJiawei Lin
186*1f0e2dc7SJiawei Lin  val entries = (0 until cfg.nMMIOEntries) map { i =>
187*1f0e2dc7SJiawei Lin    val entry = Module(new MMIOEntry(edge))
188*1f0e2dc7SJiawei Lin
189*1f0e2dc7SJiawei Lin    entry.io.id := i.U(log2Up(cfg.nMMIOEntries).W)
190*1f0e2dc7SJiawei Lin
191*1f0e2dc7SJiawei Lin    // entry req
192*1f0e2dc7SJiawei Lin    entry.io.req.valid := (i.U === entry_alloc_idx) && req.valid
193*1f0e2dc7SJiawei Lin    entry.io.req.bits  := req.bits
194*1f0e2dc7SJiawei Lin    when (i.U === entry_alloc_idx) {
195*1f0e2dc7SJiawei Lin      req_ready := entry.io.req.ready
196*1f0e2dc7SJiawei Lin    }
197*1f0e2dc7SJiawei Lin
198*1f0e2dc7SJiawei Lin    // entry resp
199*1f0e2dc7SJiawei Lin    resp_arb.io.in(i) <> entry.io.resp
200*1f0e2dc7SJiawei Lin
201*1f0e2dc7SJiawei Lin    entry.io.mem_grant.valid := false.B
202*1f0e2dc7SJiawei Lin    entry.io.mem_grant.bits  := DontCare
203*1f0e2dc7SJiawei Lin    when (mem_grant.bits.source === i.U) {
204*1f0e2dc7SJiawei Lin      entry.io.mem_grant <> mem_grant
205*1f0e2dc7SJiawei Lin    }
206*1f0e2dc7SJiawei Lin    entry
207*1f0e2dc7SJiawei Lin  }
208*1f0e2dc7SJiawei Lin
209*1f0e2dc7SJiawei Lin  entry_alloc_idx    := PriorityEncoder(entries.map(m=>m.io.req.ready))
210*1f0e2dc7SJiawei Lin
211*1f0e2dc7SJiawei Lin  req.ready  := req_ready
212*1f0e2dc7SJiawei Lin  resp          <> resp_arb.io.out
213*1f0e2dc7SJiawei Lin  TLArbiter.lowestFromSeq(edge, mem_acquire, entries.map(_.io.mem_acquire))
214*1f0e2dc7SJiawei Lin
215*1f0e2dc7SJiawei Lin
216*1f0e2dc7SJiawei Lin  // print all input/output requests for debug purpose
217*1f0e2dc7SJiawei Lin
218*1f0e2dc7SJiawei Lin  // print req/resp
219*1f0e2dc7SJiawei Lin  XSDebug(req.fire(), "req cmd: %x addr: %x data: %x mask: %x\n",
220*1f0e2dc7SJiawei Lin    req.bits.cmd, req.bits.addr, req.bits.data, req.bits.mask)
221*1f0e2dc7SJiawei Lin  XSDebug(resp.fire(), "data: %x\n", req.bits.data)
222*1f0e2dc7SJiawei Lin
223*1f0e2dc7SJiawei Lin  // print tilelink messages
224*1f0e2dc7SJiawei Lin  when(mem_acquire.valid){
225*1f0e2dc7SJiawei Lin    XSDebug("mem_acquire valid, ready=%d ", mem_acquire.ready)
226*1f0e2dc7SJiawei Lin    mem_acquire.bits.dump
227*1f0e2dc7SJiawei Lin  }
228*1f0e2dc7SJiawei Lin  when (mem_grant.fire()) {
229*1f0e2dc7SJiawei Lin    XSDebug("mem_grant fire ")
230*1f0e2dc7SJiawei Lin    mem_grant.bits.dump
231*1f0e2dc7SJiawei Lin  }
232*1f0e2dc7SJiawei Lin}
233