xref: /XiangShan/src/main/scala/xiangshan/backend/fu/NewCSR/TrapHandleModule.scala (revision 211d620b07edb797ba35b635d24fef4e7294bae2)
1package xiangshan.backend.fu.NewCSR
2
3import chisel3._
4import chisel3.util._
5import xiangshan.ExceptionNO
6import xiangshan.backend.fu.NewCSR.CSRBundles.{CauseBundle, PrivState, XtvecBundle}
7import xiangshan.backend.fu.NewCSR.CSRDefines.XtvecMode
8import xiangshan.backend.fu.NewCSR.CSRBundleImplicitCast._
9
10
11class TrapHandleModule extends Module {
12  val io = IO(new TrapHandleIO)
13
14  private val trapInfo = io.in.trapInfo
15  private val privState = io.in.privState
16  private val mstatus  = io.in.mstatus
17  private val vsstatus = io.in.vsstatus
18  private val mnstatus = io.in.mnstatus
19  private val mideleg = io.in.mideleg.asUInt
20  private val hideleg = io.in.hideleg.asUInt
21  private val medeleg = io.in.medeleg.asUInt
22  private val hedeleg = io.in.hedeleg.asUInt
23  private val mvien = io.in.mvien.asUInt
24  private val hvien = io.in.hvien.asUInt
25  private val virtualInterruptIsHvictlInject = io.in.virtualInterruptIsHvictlInject
26
27  private val hasTrap = trapInfo.valid
28  private val hasNMI = hasTrap && trapInfo.bits.nmi
29  private val hasIR = hasTrap && trapInfo.bits.isInterrupt
30  private val hasEX = hasTrap && !trapInfo.bits.isInterrupt
31
32  private val exceptionVec = io.in.trapInfo.bits.trapVec
33  private val intrVec = io.in.trapInfo.bits.intrVec
34  private val hasEXVec = Mux(hasEX, exceptionVec, 0.U)
35  private val hasIRVec = Mux(hasIR, intrVec, 0.U)
36
37  private val interruptGroups: Seq[(Seq[Int], String)] = Seq(
38    InterruptNO.customHighestGroup    -> "customHighest",
39    InterruptNO.localHighGroup        -> "localHigh",
40    InterruptNO.customMiddleHighGroup -> "customMiddleHigh",
41    InterruptNO.interruptDefaultPrio  -> "privArch",
42    InterruptNO.customMiddleLowGroup  -> "customMiddleLow",
43    InterruptNO.localLowGroup         -> "localLow",
44    InterruptNO.customLowestGroup     -> "customLowest",
45  )
46
47  private val filteredIRQs: Seq[UInt] = interruptGroups.map {
48    case (irqGroup, name) => (getMaskFromIRQGroup(irqGroup) & hasIRVec).suggestName(s"filteredIRQs_$name")
49  }
50  private val hasIRQinGroup: Seq[Bool] = interruptGroups.map {
51    case (irqGroup, name) => dontTouch(Cat(filterIRQs(irqGroup, hasIRVec)).orR.suggestName(s"hasIRQinGroup_$name"))
52  }
53
54  private val highestIRQinGroup: Seq[Vec[Bool]] = interruptGroups zip filteredIRQs map {
55    case ((irqGroup: Seq[Int], name), filteredIRQ: UInt) =>
56      produceHighIRInGroup(irqGroup, filteredIRQ).suggestName(s"highestIRQinGroup_$name")
57  }
58
59  private val highestPrioIRVec: Vec[Bool] = MuxCase(
60    0.U.asTypeOf(Vec(64, Bool())),
61    hasIRQinGroup zip highestIRQinGroup map{ case (hasIRQ: Bool, highestIRQ: Vec[Bool]) => hasIRQ -> highestIRQ }
62  )
63  private val highestPrioNMIVec = Wire(Vec(64, Bool()))
64  highestPrioNMIVec.zipWithIndex.foreach { case (irq, i) =>
65    if (NonMaskableIRNO.interruptDefaultPrio.contains(i)) {
66      val higherIRSeq = NonMaskableIRNO.getIRQHigherThan(i)
67      irq := (
68        higherIRSeq.nonEmpty.B && Cat(higherIRSeq.map(num => !hasIRVec(num))).andR ||
69          higherIRSeq.isEmpty.B
70        ) && hasIRVec(i)
71      dontTouch(irq)
72    } else
73      irq := false.B
74  }
75
76  private val highestPrioEXVec = Wire(Vec(64, Bool()))
77  highestPrioEXVec.zipWithIndex.foreach { case (excp, i) =>
78    if (ExceptionNO.priorities.contains(i)) {
79      val higherEXSeq = ExceptionNO.getHigherExcpThan(i)
80      excp := (
81        higherEXSeq.nonEmpty.B && Cat(higherEXSeq.map(num => !hasEXVec(num))).andR ||
82        higherEXSeq.isEmpty.B
83      ) && hasEXVec(i)
84    } else
85      excp := false.B
86  }
87
88  private val highestPrioIR  = highestPrioIRVec.asUInt
89  private val highestPrioNMI = highestPrioNMIVec.asUInt
90  private val highestPrioEX  = highestPrioEXVec.asUInt
91
92
93  private val mIRVec  = dontTouch(WireInit(highestPrioIR))
94  private val hsIRVec = (mIRVec  & mideleg) | (mIRVec  & mvien & ~mideleg)
95  private val vsIRVec = (hsIRVec & hideleg) | (hsIRVec & hvien & ~hideleg)
96
97  private val mEXVec  = highestPrioEX
98  private val hsEXVec = highestPrioEX & medeleg
99  private val vsEXVec = highestPrioEX & medeleg & hedeleg
100
101  // nmi handle in MMode only and default handler is mtvec
102  private val  mHasIR =  mIRVec.orR
103  private val hsHasIR = hsIRVec.orR & !hasNMI
104  private val vsHasIR = (vsIRVec.orR || hasIR && virtualInterruptIsHvictlInject) & !hasNMI
105
106  private val  mHasEX =  mEXVec.orR
107  private val hsHasEX = hsEXVec.orR
108  private val vsHasEX = vsEXVec.orR
109
110  private val  mHasTrap =  mHasEX ||  mHasIR
111  private val hsHasTrap = hsHasEX || hsHasIR
112  private val vsHasTrap = vsHasEX || vsHasIR
113
114  private val handleTrapUnderHS = !privState.isModeM && hsHasTrap
115  private val handleTrapUnderVS = privState.isVirtual && vsHasTrap
116  private val handleTrapUnderM = !handleTrapUnderVS && !handleTrapUnderHS
117
118  // Todo: support more interrupt and exception
119  private val exceptionRegular = OHToUInt(highestPrioEX)
120  private val interruptNO = OHToUInt(Mux(hasNMI, highestPrioNMI, highestPrioIR))
121  private val exceptionNO = Mux(trapInfo.bits.singleStep, ExceptionNO.breakPoint.U, exceptionRegular)
122
123  private val causeNO = Mux(hasIR, interruptNO, exceptionNO)
124
125  // sm/ssdbltrp
126  private val m_EX_DT  = handleTrapUnderM  && mstatus.MDT.asBool  && hasTrap
127  private val s_EX_DT  = handleTrapUnderHS && mstatus.SDT.asBool  && hasTrap
128  private val vs_EX_DT = handleTrapUnderVS && vsstatus.SDT.asBool && hasTrap
129
130  private val dbltrpToMN = m_EX_DT && mnstatus.NMIE.asBool // NMI not allow double trap
131  private val hasDTExcp  = m_EX_DT || s_EX_DT || vs_EX_DT
132
133  private val trapToHS = handleTrapUnderHS && !s_EX_DT && !vs_EX_DT
134  private val traptoVS = handleTrapUnderVS && !vs_EX_DT
135
136  private val xtvec = MuxCase(io.in.mtvec, Seq(
137    traptoVS -> io.in.vstvec,
138    trapToHS -> io.in.stvec
139  ))
140  private val pcFromXtvec = Cat(xtvec.addr.asUInt + Mux(xtvec.mode === XtvecMode.Vectored && hasIR, interruptNO(5, 0), 0.U), 0.U(2.W))
141
142  io.out.entryPrivState := MuxCase(default = PrivState.ModeM, mapping = Seq(
143    traptoVS -> PrivState.ModeVS,
144    trapToHS -> PrivState.ModeHS,
145  ))
146
147  io.out.causeNO.Interrupt := hasIR
148  io.out.causeNO.ExceptionCode := causeNO
149  io.out.pcFromXtvec := pcFromXtvec
150  io.out.hasDTExcp := hasDTExcp
151  io.out.dbltrpToMN := dbltrpToMN
152
153  def filterIRQs(group: Seq[Int], originIRQ: UInt): Seq[Bool] = {
154    group.map(irqNum => originIRQ(irqNum))
155  }
156
157  def getIRQHigherThanInGroup(group: Seq[Int])(irq: Int): Seq[Int] = {
158    val idx = group.indexOf(irq, 0)
159    require(idx != -1, s"The irq($irq) does not exists in IntPriority Seq")
160    group.slice(0, idx)
161  }
162
163  def getMaskFromIRQGroup(group: Seq[Int]): UInt = {
164    group.map(irq => BigInt(1) << irq).reduce(_ | _).U
165  }
166
167  def produceHighIRInGroup(irqGroup: Seq[Int], filteredIRVec: UInt): Vec[Bool] = {
168    val irVec = Wire(Vec(64, Bool()))
169    irVec.zipWithIndex.foreach { case (irq, i) =>
170      if (irqGroup.contains(i)) {
171        val higherIRSeq: Seq[Int] = getIRQHigherThanInGroup(irqGroup)(i)
172        irq := (
173          higherIRSeq.nonEmpty.B && Cat(higherIRSeq.map(num => !filteredIRVec(num))).andR ||
174            higherIRSeq.isEmpty.B
175          ) && filteredIRVec(i)
176      } else
177        irq := false.B
178    }
179    irVec
180  }
181}
182
183class TrapHandleIO extends Bundle {
184  val in = Input(new Bundle {
185    val trapInfo = ValidIO(new Bundle {
186      val trapVec = UInt(64.W)
187      val nmi = Bool()
188      val intrVec = UInt(64.W)
189      val isInterrupt = Bool()
190      val singleStep = Bool()
191    })
192    val privState = new PrivState
193    val mstatus = new MstatusBundle
194    val vsstatus = new SstatusBundle
195    val mnstatus = new MnstatusBundle
196    val mideleg = new MidelegBundle
197    val medeleg = new MedelegBundle
198    val hideleg = new HidelegBundle
199    val hedeleg = new HedelegBundle
200    val mvien = new MvienBundle
201    val hvien = new HvienBundle
202    // trap vector
203    val mtvec = Input(new XtvecBundle)
204    val stvec = Input(new XtvecBundle)
205    val vstvec = Input(new XtvecBundle)
206    // virtual interrupt is hvictl inject
207    val virtualInterruptIsHvictlInject = Input(Bool())
208  })
209
210  val out = new Bundle {
211    val entryPrivState = new PrivState
212    val causeNO = new CauseBundle
213    val dbltrpToMN = Bool()
214    val hasDTExcp = Bool()
215    val pcFromXtvec = UInt()
216  }
217}