xref: /XiangShan/src/main/scala/xiangshan/backend/fu/util/Trigger.scala (revision b03c55a5df5dc8793cb44b42dd60141566e57e78)
1package xiangshan.backend.fu.util
2
3import chisel3._
4import chisel3.util._
5import xiangshan.{XSBundle, HasXSParameter}
6import org.chipsalliance.cde.config.Parameters
7import utils.ConsecutiveOnes
8
9trait SdtrigExt extends HasXSParameter{
10  implicit val p: Parameters
11  class TDataRegs extends XSBundle {
12    val tdata1 = UInt(XLEN.W)
13    val tdata2 = UInt(XLEN.W)
14  }
15  object TDataRegs extends TDataRegs {
16    def apply() = new TDataRegs
17  }
18
19  class Tdata1Bundle extends XSBundle {
20    val type_ = TrigTypeEnum()    // [XLEN-1: XLEN-4]
21    val dmode = Bool()            // [XLEN-5]
22    val data  = new Tdata1Data    // [XLEN-6, 0]
23    require(this.getWidth == XLEN)
24    def getTriggerAction : TrigActionEnum = {
25      this.data.asTypeOf(new MControlData).action
26    }
27    def getTriggerChain: Bool = {
28      this.data.asTypeOf(new MControlData).chain
29    }
30    def getTiming: Bool = {
31      this.data.asTypeOf(new MControlData).timing
32    }
33  }
34  object Tdata1Bundle extends Tdata1Bundle {
35    def apply(): Tdata1Bundle = new Tdata1Bundle
36    def Read(rdata: UInt) : UInt = rdata
37    def Write(wdata: UInt, tdata1: UInt, chainable: Bool, debug_mode: Bool) : UInt = {
38      val tdata1_old = WireInit(tdata1.asTypeOf(new Tdata1Bundle))
39      val tdata1_new = Wire(new Tdata1Bundle)
40      val wdata_new = WireInit(wdata.asTypeOf(new Tdata1Bundle))
41      tdata1_new.type_ := wdata_new.type_.legalize
42      tdata1_new.dmode := wdata_new.dmode && debug_mode // dmode only support write in debug mode
43      when (wdata_new.type_.asUInt === TrigTypeEnum.MCONTROL) {
44        tdata1_new.data.value := MControlData.Write(wdata_new.asUInt, tdata1_old.data.asUInt, chainable)
45      }.otherwise {
46        tdata1_new.data.value := 0.U
47      }
48      tdata1_new.asUInt
49    }
50    def default : UInt = {
51      (TrigTypeEnum.disabled.litValue << (XLEN - 4)).U
52    }
53  }
54
55  class TrigTypeEnum extends Bundle {
56    val value         = UInt(4.W)
57    def NONE          = 0.U
58    def LEGACY        = 1.U
59    def MCONTROL      = 2.U
60    def ICOUNT        = 3.U
61    def ITRIGGER      = 4.U
62    def ETRIGGER      = 5.U
63    def MCONTROL6     = 6.U
64    def TMEXTTRIGGER  = 7.U
65    def disabled      = 15.U
66    /**
67     * XS supports part of trigger type of Sdtrig extension
68     * @param data trigger type checked
69     * @return true.B, If XS support this trigger type
70     */
71    def isLegal : Bool = {
72      this.asUInt === this.MCONTROL
73    }
74    def legalize : TrigTypeEnum = {
75      Mux(this.isLegal, this.asUInt, this.disabled).asTypeOf(new TrigTypeEnum)
76    }
77  }
78  object TrigTypeEnum extends TrigTypeEnum {
79    def apply()   = new TrigTypeEnum
80  }
81
82  protected class Tdata1Data extends XSBundle {
83    val value = UInt((XLEN-5).W)
84  }
85
86  class MControlData extends Tdata1Data {
87    override val value = null
88    val maskmax   = UInt(6.W)                           // [XLEN-6: XLEN-11]
89    val zero1     = if (XLEN==64) UInt(30.W) else null  // [XLEN-12: 23]
90    val sizehi    = if (XLEN==64) UInt(2.W) else null   // [22:21]
91    val hit       = Bool()                              // [20]
92    val select    = Bool()                              // [19]
93    val timing    = Bool()                              // [18]
94    val sizelo    = UInt(2.W)                           // [17:16]
95    val action    = TrigActionEnum()                    // [15:12]
96    val chain     = Bool()                              // [11]
97    val match_    = TrigMatchEnum()                     // [10:7]
98    val m         = Bool()                              // [6]
99    val zero2     = Bool()                              // [5]
100    val s         = Bool()                              // [4]
101    val u         = Bool()                              // [3]
102    val execute   = Bool()                              // [2]
103    val store     = Bool()                              // [1]
104    val load      = Bool()                              // [0]
105    require(this.getWidth == (new Tdata1Data).getWidth)
106
107    def isFetchTrigger: Bool = this.execute
108    def isMemAccTrigger: Bool = this.store || this.load
109  }
110  object MControlData {
111    def Read(rdata: UInt) : UInt = rdata
112    def Write(wdata: UInt, tdata1data: UInt, chainable: Bool) : UInt = {
113      val mcontrol_old = WireInit(tdata1data.asTypeOf(new MControlData))
114      val tdata1_new = WireInit(wdata.asTypeOf(new Tdata1Bundle))
115      val mcontrol_new = WireInit(tdata1_new.data.asTypeOf(new MControlData))
116      val wdata_new = WireInit(wdata.asTypeOf(new MControlData))
117      mcontrol_new.maskmax  := 0.U
118      mcontrol_new.zero1    := 0.U
119      mcontrol_new.sizehi   := 0.U
120      mcontrol_new.hit      := false.B
121      mcontrol_new.select   := wdata_new.execute && wdata_new.select // not support rdata/wdata trigger
122      mcontrol_new.timing   := false.B // only support trigger fires before its execution
123      mcontrol_new.sizelo   := 0.U
124      mcontrol_new.action   := wdata_new.action.legalize(tdata1_new.dmode)
125      mcontrol_new.chain    := chainable && wdata_new.chain
126      mcontrol_new.match_   := wdata_new.match_.legalize
127      mcontrol_new.zero2    := 0.U
128      mcontrol_new.asUInt
129    }
130  }
131
132  class TrigActionEnum extends Bundle {
133    val value       = UInt(4.W)
134    def BKPT_EXCPT  = 0.U // raise breakpoint exception
135    def DEBUG_MODE  = 1.U // enter debug mode
136    def TRACE_ON    = 2.U
137    def TRACE_OFF   = 3.U
138    def TRACE_NOTIFY= 4.U
139    def default     = this.BKPT_EXCPT
140    /**
141     * XS supports part of trigger action type of Sdtrig extension
142     * @param data action checked
143     * @return true.B, If XS support such trigger action type
144     */
145    def isLegal(dmode: Bool) : Bool = {
146      this.asUInt === this.BKPT_EXCPT || this.asUInt === this.DEBUG_MODE && dmode
147    }
148    def legalize(dmode: Bool) : TrigActionEnum = {
149      Mux(this.isLegal(dmode), this.asUInt, this.default).asTypeOf(new TrigActionEnum)
150    }
151  }
152  object TrigActionEnum extends TrigActionEnum {
153    def apply() = new TrigActionEnum
154  }
155
156  class TrigMatchEnum extends Bundle {
157    val value     = UInt(4.W)
158    private def not_bit = 8.U
159    def EQ        = 0.U
160    def NAPOT     = 1.U
161    def GE        = 2.U
162    def LT        = 3.U
163    def MASK_LO   = 4.U
164    def MASK_HI   = 5.U
165    def NE        = EQ      | this.not_bit // not eq
166    def NNAPOT    = NAPOT   | this.not_bit // not napot
167    def NMASK_LO  = MASK_LO | this.not_bit // not mask low
168    def NMASK_HI  = MASK_HI | this.not_bit // not mask high
169    def default   = this.EQ
170    def isRVSpecLegal : Bool = {
171      this.asUInt === this.EQ || this.asUInt === this.NAPOT ||
172        this.asUInt === this.GE || this.asUInt === this.LT ||
173        this.asUInt === this.MASK_LO || this.asUInt === this.MASK_HI ||
174        this.asUInt === this.NE || this.asUInt === this.NNAPOT ||
175        this.asUInt === this.NMASK_LO || this.asUInt === this.NMASK_HI
176    }
177
178    /**
179     * XS supports part of trigger match type of Sdtrig extension
180     * @param data match type checked
181     * @return true.B, If XS support such trigger match type
182     */
183    def isLegal : Bool = {
184      this.asUInt === this.EQ || this.asUInt === this.GE || this.asUInt === this.LT
185    }
186    def legalize : TrigMatchEnum = {
187      Mux(this.isLegal, this.asUInt, this.default).asTypeOf(new TrigMatchEnum)
188    }
189  }
190  object TrigMatchEnum extends TrigMatchEnum {
191    def apply() = new TrigMatchEnum
192  }
193
194  /**
195   * Check if triggers can fire
196   * @param triggerNum
197   * @param canFireVec
198   * @param hitVec
199   * @param timingVec
200   * @param chainVec
201   */
202  def TriggerCheckCanFire(triggerNum: Int, canFireVec: Vec[Bool], hitVec: Vec[Bool], timingVec: Vec[Bool], chainVec: Vec[Bool]): Unit = {
203    val trigger2ChainVec = WireInit(VecInit(Seq.fill(triggerNum)(false.B)))
204    val trigger2TimingSameVec = WireInit(VecInit(Seq.fill(triggerNum)(true.B)))
205    val trigger2TimingOkVec = WireInit(VecInit(Seq.fill(triggerNum)(true.B)))
206    val trigger2ChainOkVec = WireInit(VecInit(Seq.fill(triggerNum)(true.B)))
207    for (i <- 1 until triggerNum) { // the 0th trigger always chain ok
208      trigger2ChainOkVec(i) := chainVec(i - 1) && hitVec(i - 1) || !chainVec(i - 1)
209    }
210
211    for (i <- 1 until triggerNum) { // the 0th trigger always timing same, not chain, timing ok
212      trigger2TimingSameVec(i) := timingVec(i - 1) === timingVec(i)
213      trigger2ChainVec(i) := chainVec(i - 1) && !chainVec(i)
214      trigger2TimingOkVec(i) := trigger2ChainVec(i) && trigger2TimingSameVec(i) || !chainVec(i - 1)
215    }
216    canFireVec.zipWithIndex.foreach {
217      case (canFire, i) => canFire := trigger2ChainOkVec(i) && trigger2TimingOkVec(i) && hitVec(i) && !chainVec(i)
218    }
219  }
220
221  /**
222   * Check if chain vector is legal
223   * @param chainVec
224   * @param chainLen
225   * @return true.B if the max length of chain don't exceed the permitted length
226   */
227  def TriggerCheckChainLegal(chainVec: Seq[Bool], chainLen: Int): Bool = {
228    !ConsecutiveOnes(chainVec, chainLen)
229  }
230
231  /**
232   * Compare data with trigger data
233   * @param data data compared
234   * @param tdata data from trigger
235   * @param matchType trigger match type in UInt
236   * @param enable if the trigger is enabled
237   * @return true.B if data meet the trigger match condition
238   */
239  def TriggerCmp(data: UInt, tdata: UInt, matchType: UInt, enable: Bool): Bool = {
240    val eq = data(VAddrBits - 1, 0) === tdata(VAddrBits - 1, 0)
241    val ge = data(VAddrBits - 1, 0) >= tdata(VAddrBits - 1, 0)
242    val lt = data(VAddrBits - 1, 0) < tdata(VAddrBits - 1, 0)
243    val res = MuxLookup(matchType, false.B)(Seq(
244      TrigMatchEnum.EQ -> eq,
245      TrigMatchEnum.GE -> ge,
246      TrigMatchEnum.LT -> lt
247    ))
248    res && enable
249  }
250
251  /**
252   * author @Guokai Chen
253   * compare between Consecutive pc and tdada2
254   */
255  def TriggerCmpConsecutive(pcVec: Vec[UInt], tdata: UInt, matchType: UInt, enable: Bool) : Vec[Bool] = {
256    // opt: only compare two possible high bits: orig and orig+1
257    val pcVecWidth = pcVec.length
258    // also take care of that triggerMatch is less
259    val highPos = log2Up(pcVecWidth) + 1
260
261    val lowPCVec = Wire(Vec(pcVecWidth, UInt(highPos.W)))
262    lowPCVec.zipWithIndex.map{case (h, i) => h := pcVec(i)(highPos - 1, 0)}
263    val highPC = pcVec(0)(VAddrBits - 1, highPos)
264    val highPC1 = pcVec(0)(VAddrBits - 1, highPos) + 1.U
265
266    val lowTdata = tdata(highPos - 1, 0)
267    val highTdata = tdata(VAddrBits - 1, highPos)
268
269    val highPCEqual = highPC === highTdata
270    val highPC1Equal = highPC1 === highTdata
271    val highPCGreater = highPC > highTdata
272    val highPC1Greater = highPC1 > highTdata
273    val highPCLess = highPC < highTdata
274    val highPC1Less = highPC1 < highTdata
275
276    val carry = Wire(Vec(pcVecWidth, Bool()))
277    carry.zipWithIndex.map{case (c, i) => c := pcVec(i)(highPos) =/= pcVec(0)(highPos)}
278
279    val lowPCEqual = Wire(Vec(pcVecWidth, Bool()))
280    val lowPCGreater = Wire(Vec(pcVecWidth, Bool()))
281    val lowPCLess = Wire(Vec(pcVecWidth, Bool()))
282
283    lowPCEqual.zipWithIndex.map{case (l, i) => l := lowPCVec(i) === lowTdata }
284    lowPCGreater.zipWithIndex.map{case (l, i) => l :=  lowPCVec(i) >= lowTdata }
285    lowPCLess.zipWithIndex.map{case (l, i) => l :=  lowPCVec(i) < lowTdata }
286
287    val overallEqual = Wire(Vec(pcVecWidth, Bool()))
288    val overallGreater = Wire(Vec(pcVecWidth, Bool()))
289    val overallLess = Wire(Vec(pcVecWidth, Bool()))
290
291    overallEqual.zipWithIndex.map{case (o, i) => o :=
292      (!carry(i) && lowPCEqual(i) && highPCEqual) ||
293        carry(i) && highPC1Equal && lowPCEqual(i)
294    }
295
296    // [left : greater 1. nonCarry 2. carry
297    overallGreater.zipWithIndex.map { case (o, i) => o :=
298      !carry(i) && (highPCGreater || highPCEqual && lowPCGreater(i)) ||
299       carry(i) && (highPCGreater || highPCEqual || highPC1Equal && lowPCGreater(i))
300    }
301
302    // right) : less 1. nonCarryRight 2. carryRight
303    val carryRight = Wire(Vec(pcVecWidth, Bool()))
304    carryRight.zipWithIndex.map{case (c, i) => c := pcVec(i)(highPos) =/= pcVec(pcVecWidth - 1)(highPos)}
305
306    overallLess.zipWithIndex.map { case (o, i) => o :=
307      !carryRight(i) && (highPCLess || highPCEqual && lowPCLess(i)) ||
308       carryRight(i) && (highPC1Less || highPC1Equal || highPCEqual && lowPCLess(i))
309    }
310
311    val ret = Wire(Vec(pcVecWidth, Bool()))
312    ret.zipWithIndex.map{case (r, i) => r := MuxLookup(matchType, false.B)(
313      Seq(
314        TrigMatchEnum.EQ -> overallEqual(i),
315        TrigMatchEnum.GE -> overallGreater(i),
316        TrigMatchEnum.LT -> overallLess(i))) && enable}
317    ret
318  }
319}
320