xref: /XiangShan/src/main/scala/xiangshan/backend/fu/NewCSR/Debug.scala (revision 3c808de005aba6d7539d33be9962c44375b97e6d)
1package xiangshan.backend.fu.NewCSR
2
3import chisel3._
4import chisel3.util._
5import org.chipsalliance.cde.config.Parameters
6import xiangshan.cache.HasDCacheParameters
7import xiangshan.backend.fu.NewCSR.CSRBundles.PrivState
8import xiangshan.backend.fu.util.CSRConst
9import xiangshan.backend.fu.util.SdtrigExt
10import xiangshan._
11import utils._
12
13class Debug(implicit val p: Parameters) extends Module with HasXSParameter {
14  val io = IO(new DebugIO)
15
16  private val trapInfo        = io.in.trapInfo
17  private val hasTrap         = trapInfo.valid
18  private val trapIsInterrupt = trapInfo.bits.isInterrupt
19  private val isDebugIntr     = trapInfo.bits.isDebugIntr
20  private val trapVec         = trapInfo.bits.trapVec
21  private val singleStep      = trapInfo.bits.singleStep
22  private val trigger         = io.in.trapInfo.bits.trigger
23
24  private val privState = io.in.privState
25  private val debugMode = io.in.debugMode
26
27  private val dcsr = io.in.dcsr
28  private val tselect = io.in.tselect
29  private val tdata1Selected = io.in.tdata1Selected
30  private val tdata2Selected = io.in.tdata2Selected
31  private val tdata1Vec = io.in.tdata1Vec
32
33  private val tdata1Update  = io.in.tdata1Update
34  private val tdata2Update  = io.in.tdata2Update
35  private val tdata1Wdata   = io.in.tdata1Wdata
36
37  /**
38   * ways to entry Dmode:
39   *    1. debug intr(from external debug module)
40   *    2. ebreak inst in nonDmode
41   *    3. trigger fire in nonDmode
42   *    4. single step(debug module set dcsr.step before hart resume)
43   *    5. critical error state(when dcsr.cetrig assert)
44   */
45  // debug_intr
46  val hasIntr = hasTrap && trapIsInterrupt
47  val hasDebugIntr = hasIntr && isDebugIntr
48
49  // debug_exception_ebreak
50  val hasExp = hasTrap && !trapIsInterrupt
51  val breakPoint = trapVec(ExceptionNO.breakPoint).asBool
52  val isEbreak = hasExp && breakPoint && !TriggerAction.isExp(trigger)
53  val ebreakEnterDebugMode =
54    (privState.isModeM && dcsr.EBREAKM.asBool) ||
55      (privState.isModeHS && dcsr.EBREAKS.asBool) ||
56      (privState.isModeHU && dcsr.EBREAKU.asBool) ||
57      (privState.isModeVS && dcsr.EBREAKVS.asBool) ||
58      (privState.isModeVU && dcsr.EBREAKVU.asBool)
59  val hasDebugEbreakException = isEbreak && ebreakEnterDebugMode
60
61  // debug_exception_trigger
62  val mcontrol6WireVec = tdata1Vec.map{ mod => {
63    val mcontrol6Wire = Wire(new Mcontrol6)
64    mcontrol6Wire := mod.DATA.asUInt
65    mcontrol6Wire
66  }}
67
68  val triggerCanRaiseBpExp = io.in.triggerCanRaiseBpExp
69  val triggerEnterDebugMode = hasExp && TriggerAction.isDmode(trigger)
70
71  // debug_exception_single
72  val hasSingleStep = hasExp && singleStep
73
74
75  // critical error state
76  val criticalErrorStateEnterDebug = trapInfo.bits.criticalErrorState && dcsr.CETRIG.asBool
77
78  val hasDebugException = hasDebugEbreakException || triggerEnterDebugMode || hasSingleStep || criticalErrorStateEnterDebug
79  val hasDebugTrap = hasDebugException || hasDebugIntr
80
81  val tselect1H = UIntToOH(tselect.asUInt, TriggerNum).asBools
82  val chainVec = mcontrol6WireVec.map(_.CHAIN.asBool)
83  val newTriggerChainVec = tselect1H.zip(chainVec).map{case(a, b) => a | b}
84  val newTriggerChainIsLegal = TriggerUtil.TriggerCheckChainLegal(newTriggerChainVec, TriggerChainMaxLength)
85
86  val triggerUpdate = tdata1Update || tdata2Update
87
88  val mcontrol6Wdata = Wire(new Mcontrol6)
89  mcontrol6Wdata := tdata1Wdata.DATA.asUInt
90  val tdata1TypeWdata = tdata1Wdata.TYPE
91
92  val mcontrol6Selected = Wire(new Mcontrol6)
93  mcontrol6Selected := tdata1Selected.DATA.asUInt
94
95  val frontendTriggerUpdate =
96    tdata1Update && tdata1TypeWdata.isLegal && mcontrol6Wdata.isFetchTrigger ||
97      mcontrol6Selected.isFetchTrigger && triggerUpdate
98
99  val memTriggerUpdate =
100    tdata1Update && tdata1TypeWdata.isLegal && mcontrol6Wdata.isMemAccTrigger ||
101      mcontrol6Selected.isMemAccTrigger && triggerUpdate
102
103  val triggerEnableVec = tdata1Vec.zip(mcontrol6WireVec).map { case(tdata1, mcontrol6) =>
104    tdata1.TYPE.isLegal && (
105      mcontrol6.M && privState.isModeM  ||
106        mcontrol6.S && privState.isModeHS ||
107        mcontrol6.U && privState.isModeHU ||
108        mcontrol6.VS && privState.isModeVS ||
109        mcontrol6.VU && privState.isModeVU)
110  }
111
112  val fetchTriggerEnableVec = triggerEnableVec.zip(mcontrol6WireVec).map {
113    case (tEnable, mod) => tEnable && mod.isFetchTrigger
114  }
115  val memAccTriggerEnableVec = triggerEnableVec.zip(mcontrol6WireVec).map {
116    case (tEnable, mod) => tEnable && mod.isMemAccTrigger
117  }
118
119  io.out.frontendTrigger.tUpdate.valid        := RegNext(RegNext(frontendTriggerUpdate))
120  io.out.frontendTrigger.tUpdate.bits.addr    := tselect.asUInt
121  io.out.frontendTrigger.tUpdate.bits.tdata.GenTdataDistribute(tdata1Selected, tdata2Selected)
122  io.out.frontendTrigger.tEnableVec           := fetchTriggerEnableVec
123  io.out.frontendTrigger.triggerCanRaiseBpExp := triggerCanRaiseBpExp
124  io.out.frontendTrigger.debugMode            := debugMode
125
126  io.out.memTrigger.tUpdate.valid            := RegNext(RegNext(memTriggerUpdate))
127  io.out.memTrigger.tUpdate.bits.addr        := tselect.asUInt
128  io.out.memTrigger.tUpdate.bits.tdata.GenTdataDistribute(tdata1Selected, tdata2Selected)
129  io.out.memTrigger.tEnableVec               := memAccTriggerEnableVec
130  io.out.memTrigger.triggerCanRaiseBpExp     := triggerCanRaiseBpExp
131  io.out.memTrigger.debugMode                := debugMode
132
133  io.out.triggerFrontendChange  := frontendTriggerUpdate
134  io.out.newTriggerChainIsLegal := newTriggerChainIsLegal
135
136  io.out.hasDebugTrap                 := hasDebugTrap
137  io.out.hasDebugIntr                 := hasDebugIntr
138  io.out.hasSingleStep                := hasSingleStep
139  io.out.triggerEnterDebugMode        := triggerEnterDebugMode
140  io.out.hasDebugEbreakException      := hasDebugEbreakException
141  io.out.breakPoint                   := breakPoint
142  io.out.criticalErrorStateEnterDebug := criticalErrorStateEnterDebug
143}
144
145class DebugIO(implicit val p: Parameters) extends Bundle with HasXSParameter {
146  val in = Input(new Bundle {
147    val trapInfo = ValidIO(new Bundle {
148      val trapVec = UInt(64.W)
149      val isDebugIntr = Bool()
150      val isInterrupt = Bool()
151      val singleStep = Bool()
152      val trigger = TriggerAction()
153      val criticalErrorState = Bool()
154    })
155
156    val privState = new PrivState
157    val debugMode = Bool()
158
159    val dcsr = new DcsrBundle
160    val tselect = new TselectBundle(TriggerNum)
161    val tdata1Selected = new Tdata1Bundle
162    val tdata2Selected = new Tdata2Bundle
163    val tdata1Vec = Vec(TriggerNum, new Tdata1Bundle)
164    val triggerCanRaiseBpExp = Bool()
165
166    val tdata1Update = Bool()
167    val tdata2Update = Bool()
168    val tdata1Wdata = new Tdata1Bundle
169  })
170
171  val out = Output(new Bundle{
172    // trigger
173    val triggerFrontendChange = Bool()
174    val newTriggerChainIsLegal = Bool()
175    val memTrigger = new MemTdataDistributeIO()
176    val frontendTrigger = new FrontendTdataDistributeIO()
177
178    val hasDebugTrap = Bool()
179    val hasDebugIntr = Bool()
180    val hasSingleStep = Bool()
181    val triggerEnterDebugMode = Bool()
182    val hasDebugEbreakException = Bool()
183    val breakPoint = Bool()
184    val criticalErrorStateEnterDebug = Bool()
185  })
186}
187
188class CsrTriggerBundle(implicit val p: Parameters) extends Bundle with HasXSParameter {
189  val tdataVec = Vec(TriggerNum, new MatchTriggerIO)
190  val tEnableVec = Vec(TriggerNum, Bool())
191  val debugMode = Bool()
192  val triggerCanRaiseBpExp = Bool()
193}
194
195object MemType {
196  val LOAD  = true
197  val STORE = false
198}
199
200
201class BaseTriggerIO(implicit p: Parameters) extends XSBundle{
202  val fromCsrTrigger = Input(new CsrTriggerBundle)
203
204  val fromLoadStore = Input(new Bundle {
205    val vaddr = UInt(VAddrBits.W)
206    val isVectorUnitStride = Bool()
207    val mask = UInt((VLEN/8).W)
208  })
209
210  val toLoadStore = Output(new Bundle{
211    val triggerAction = TriggerAction()
212    val triggerVaddr  = UInt(VAddrBits.W)
213    val triggerMask  = UInt((VLEN/8).W)
214  })
215}
216
217
218abstract class BaseTrigger()(implicit val p: Parameters) extends Module with HasXSParameter with SdtrigExt with HasDCacheParameters {
219  lazy val io = IO(new BaseTriggerIO)
220
221  def getTriggerHitVec(): Vec[Bool]
222  def highBitsEq(): Vec[Bool]
223  def DcacheLineBitsEq(): (Bool, Vec[Bool])
224
225  val tdataVec      = io.fromCsrTrigger.tdataVec
226  val tEnableVec    = io.fromCsrTrigger.tEnableVec
227  val triggerCanRaiseBpExp = io.fromCsrTrigger.triggerCanRaiseBpExp
228  val debugMode = io.fromCsrTrigger.debugMode
229  val vaddr = io.fromLoadStore.vaddr
230
231  val triggerTimingVec = VecInit(tdataVec.map(_.timing))
232  val triggerChainVec = VecInit(tdataVec.map(_.chain))
233
234  // Trigger can't hit/fire in debug mode.
235  val triggerHitVec = getTriggerHitVec()
236  val triggerCanFireVec = WireInit(VecInit(Seq.fill(TriggerNum)(false.B)))
237  // for vector unit-stride, match Type only support equal
238  val lowBitWidth = log2Up(VLEN/8)
239  val isVectorStride = io.fromLoadStore.isVectorUnitStride
240  val mask = io.fromLoadStore.mask
241
242  val (isCacheLine, cacheLineEq) = DcacheLineBitsEq()
243
244  val highEq = highBitsEq()
245
246  val lowMatch = tdataVec.map(tdata => UIntToOH(tdata.tdata2(lowBitWidth-1, 0)) & mask)
247  val lowEq  = VecInit(lowMatch.map(lm => lm.orR))
248
249  val hitVecVectorStride  = VecInit(highEq.zip(lowEq).map{case(hi, lo) => hi && lo})
250
251  val tiggerVaddrHit = Mux(isCacheLine, cacheLineEq, Mux(isVectorStride, hitVecVectorStride, triggerHitVec))
252  TriggerCheckCanFire(TriggerNum, triggerCanFireVec, tiggerVaddrHit, triggerTimingVec, triggerChainVec)
253  val triggerFireOH = PriorityEncoderOH(triggerCanFireVec)
254  val triggerVaddr  = PriorityMux(triggerFireOH, VecInit(tdataVec.map(_.tdata2))).asUInt
255  val triggerMask   = PriorityMux(triggerFireOH, VecInit(tdataVec.map(x => UIntToOH(x.tdata2(lowBitWidth-1, 0))))).asUInt
256
257  val actionVec = VecInit(tdataVec.map(_.action))
258  val triggerAction = Wire(TriggerAction())
259  TriggerUtil.triggerActionGen(triggerAction, triggerCanFireVec, actionVec, triggerCanRaiseBpExp)
260
261  io.toLoadStore.triggerAction := triggerAction
262  io.toLoadStore.triggerVaddr  := triggerVaddr
263  io.toLoadStore.triggerMask   := triggerMask
264}
265
266
267class MemTrigger(memType: Boolean = MemType.LOAD)(override implicit val p: Parameters) extends BaseTrigger {
268
269  class MemTriggerIO extends BaseTriggerIO{
270    val isCbo = OptionWrapper(memType == MemType.STORE, Input(Bool()))
271  }
272
273  override lazy val io = IO(new MemTriggerIO)
274
275  override def getTriggerHitVec(): Vec[Bool] = {
276    val triggerHitVec = WireInit(VecInit(Seq.fill(TriggerNum)(false.B)))
277    for (i <- 0 until TriggerNum) {
278      triggerHitVec(i) := !tdataVec(i).select && !debugMode && TriggerCmp(
279      vaddr,
280      tdataVec(i).tdata2,
281      tdataVec(i).matchType,
282      tEnableVec(i) && (if(memType == MemType.LOAD) tdataVec(i).load else tdataVec(i).store)
283      )
284    }
285    triggerHitVec
286  }
287
288  override def highBitsEq(): Vec[Bool] = {
289    VecInit(tdataVec.zip(tEnableVec).map{ case(tdata, en) =>
290      !tdata.select && !debugMode && en &&
291        (if(memType == MemType.LOAD) tdata.load else tdata.store) &&
292        (vaddr >> lowBitWidth) === (tdata.tdata2 >> lowBitWidth)
293    })
294  }
295
296  def DcacheLineBitsEq(): (Bool, Vec[Bool])= {
297    (
298    io.isCbo.getOrElse(false.B),
299    VecInit(tdataVec.zip(tEnableVec).map{ case(tdata, en) =>
300      !tdata.select && !debugMode && en &&
301        tdata.store && io.isCbo.getOrElse(false.B) &&
302        (vaddr >> DCacheLineOffset) === (tdata.tdata2 >> DCacheLineOffset)
303    })
304    )
305  }
306
307}
308
309class VSegmentTrigger(override implicit val p: Parameters) extends BaseTrigger {
310
311  class VSegmentTriggerIO extends BaseTriggerIO{
312    val memType = Input(Bool())
313  }
314
315  override lazy val io = IO(new VSegmentTriggerIO)
316
317  override def getTriggerHitVec(): Vec[Bool] = {
318    val triggerHitVec = WireInit(VecInit(Seq.fill(TriggerNum)(false.B)))
319    for (i <- 0 until TriggerNum) {
320      triggerHitVec(i) := !tdataVec(i).select && !debugMode && TriggerCmp(
321        vaddr,
322        tdataVec(i).tdata2,
323        tdataVec(i).matchType,
324        tEnableVec(i) && Mux(io.memType === MemType.LOAD.asBool, tdataVec(i).load, tdataVec(i).store)
325      )
326    }
327    triggerHitVec
328  }
329
330  override def highBitsEq(): Vec[Bool] = {
331    VecInit(tdataVec.zip(tEnableVec).map{ case(tdata, en) =>
332      !tdata.select && !debugMode && en &&
333        Mux(io.memType === MemType.LOAD.asBool, tdata.load, tdata.store) &&
334        (vaddr >> lowBitWidth) === (tdata.tdata2 >> lowBitWidth)
335    })
336  }
337
338  // vector segment does not have a cbo
339  def DcacheLineBitsEq(): (Bool, Vec[Bool]) = {
340    (false.B, VecInit(Seq.fill(tdataVec.length)(false.B)))
341  }
342}