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