xref: /XiangShan/src/main/scala/xiangshan/cache/dcache/mainpipe/Probe.scala (revision 708ceed4afe43fb0ea3a52407e46b2794c573634)
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.cache
18
19import chipsalliance.rocketchip.config.Parameters
20import chisel3._
21import chisel3.util._
22
23import freechips.rocketchip.tilelink.{TLEdgeOut, TLBundleB, TLMessages, TLPermissions}
24
25import utils.{HasTLDump, XSDebug, XSPerfAccumulate}
26
27class ProbeReq(implicit p: Parameters) extends DCacheBundle
28{
29  val source = UInt()
30  val opcode = UInt()
31  val addr   = UInt(PAddrBits.W)
32  // TODO: l2 should use vaddr index to probe l1
33  val vaddr  = UInt(VAddrBits.W)
34  val param  = UInt(TLPermissions.bdWidth.W)
35  val needData = Bool()
36
37  def dump() = {
38    XSDebug("ProbeReq source: %d opcode: %d addr: %x param: %d\n",
39      source, opcode, addr, param)
40  }
41}
42
43class ProbeEntry(implicit p: Parameters) extends DCacheModule {
44  val io = IO(new Bundle {
45    val req = Flipped(Decoupled(new ProbeReq))
46    val pipe_req  = DecoupledIO(new MainPipeReq)
47    val lrsc_locked_block = Input(Valid(UInt()))
48
49    // the block we are probing
50    val block_addr  = Output(Valid(UInt()))
51  })
52
53  val s_invalid :: s_pipe_req :: Nil = Enum(2)
54
55  val state = RegInit(s_invalid)
56
57  val req = Reg(new ProbeReq)
58
59  // assign default values to signals
60  io.req.ready      := false.B
61  io.pipe_req.valid := false.B
62  io.pipe_req.bits  := DontCare
63
64  io.block_addr.valid := state =/= s_invalid
65  io.block_addr.bits  := req.addr
66
67  when (state =/= s_invalid) {
68    XSDebug("state: %d\n", state)
69  }
70
71  when (state =/= s_invalid) {
72    XSDebug("ProbeEntry: state: %d block_addr: %x\n", state, io.block_addr.bits)
73  }
74
75  when (state === s_invalid) {
76    io.req.ready := true.B
77    when (io.req.fire()) {
78      req := io.req.bits
79      state := s_pipe_req
80    }
81  }
82
83  when (state === s_pipe_req) {
84    val lrsc_blocked = io.lrsc_locked_block.valid && io.lrsc_locked_block.bits === req.addr
85    io.pipe_req.valid := !lrsc_blocked
86
87    val pipe_req = io.pipe_req.bits
88    pipe_req := DontCare
89    pipe_req.miss := false.B
90    pipe_req.probe := true.B
91    pipe_req.probe_param := req.param
92    pipe_req.addr   := req.addr
93    pipe_req.vaddr  := req.vaddr
94    pipe_req.probe_need_data := req.needData
95
96    when (io.pipe_req.fire()) {
97      state := s_invalid
98    }
99  }
100
101  // perfoemance counters
102  XSPerfAccumulate("probe_req", state === s_invalid && io.req.fire())
103  XSPerfAccumulate("probe_penalty", state =/= s_invalid)
104  XSPerfAccumulate("probe_penalty_blocked_by_lrsc", state === s_pipe_req && io.lrsc_locked_block.valid && io.lrsc_locked_block.bits === req.addr)
105  XSPerfAccumulate("probe_penalty_blocked_by_pipeline", state === s_pipe_req && io.pipe_req.valid && !io.pipe_req.ready)
106}
107
108class ProbeQueue(edge: TLEdgeOut)(implicit p: Parameters) extends DCacheModule with HasTLDump
109{
110  val io = IO(new Bundle {
111    val mem_probe = Flipped(Decoupled(new TLBundleB(edge.bundle)))
112    val pipe_req  = DecoupledIO(new MainPipeReq)
113    val lrsc_locked_block = Input(Valid(UInt()))
114  })
115
116  val pipe_req_arb = Module(new RRArbiter(new MainPipeReq, cfg.nProbeEntries))
117
118  // allocate a free entry for incoming request
119  val primary_ready  = Wire(Vec(cfg.nProbeEntries, Bool()))
120  val allocate = primary_ready.asUInt.orR
121  val alloc_idx = PriorityEncoder(primary_ready)
122
123  // translate to inner req
124  val req = Wire(new ProbeReq)
125  val alias_addr_frag = io.mem_probe.bits.data(2, 1) // add extra 2 bits from vaddr to get vindex
126  req.source := io.mem_probe.bits.source
127  req.opcode := io.mem_probe.bits.opcode
128  req.addr := io.mem_probe.bits.address
129  if(DCacheAboveIndexOffset > DCacheTagOffset) {
130    // have alias problem, extra alias bits needed for index
131    req.vaddr := Cat(
132      io.mem_probe.bits.address(VAddrBits - 1, DCacheAboveIndexOffset), // dontcare
133      alias_addr_frag(DCacheAboveIndexOffset - DCacheTagOffset - 1, 0), // index
134      io.mem_probe.bits.address(DCacheTagOffset - 1, 0)                 // index & others
135    )
136  } else { // no alias problem
137    req.vaddr := io.mem_probe.bits.address
138  }
139  req.param := io.mem_probe.bits.param
140  req.needData := io.mem_probe.bits.data(0)
141
142  io.mem_probe.ready := allocate
143
144  val entries = (0 until cfg.nProbeEntries) map { i =>
145    val entry = Module(new ProbeEntry)
146
147    // entry req
148    entry.io.req.valid := (i.U === alloc_idx) && allocate && io.mem_probe.valid
149    primary_ready(i)   := entry.io.req.ready
150    entry.io.req.bits  := req
151
152    // pipe_req
153    pipe_req_arb.io.in(i) <> entry.io.pipe_req
154
155    entry.io.lrsc_locked_block := io.lrsc_locked_block
156
157    entry
158  }
159
160  io.pipe_req <> pipe_req_arb.io.out
161
162  // print all input/output requests for debug purpose
163  when (io.mem_probe.valid) {
164    // before a probe finishes, L2 should not further issue probes on this block
165    val probe_conflict = VecInit(entries.map(e => e.io.block_addr.valid && e.io.block_addr.bits === io.mem_probe.bits.address)).asUInt.orR
166    assert (!probe_conflict)
167    // for now, we can only deal with ProbeBlock
168    assert (io.mem_probe.bits.opcode === TLMessages.Probe)
169  }
170
171  // debug output
172  when (io.mem_probe.fire()) {
173    XSDebug("mem_probe: ")
174    io.mem_probe.bits.dump
175  }
176
177  when (io.pipe_req.fire()) {
178    io.pipe_req.bits.dump()
179  }
180
181  when (io.lrsc_locked_block.valid) {
182    XSDebug("lrsc_locked_block: %x\n", io.lrsc_locked_block.bits)
183  }
184}
185