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