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