1package xiangshan.backend.fu.NewCSR.CSREvents 2 3import chisel3._ 4import chisel3.util._ 5import org.chipsalliance.cde.config.Parameters 6import utility.{SignExt, ZeroExt} 7import xiangshan.{ExceptionNO, HasXSParameter} 8import xiangshan.ExceptionNO._ 9import xiangshan.backend.fu.NewCSR.CSRBundles.{CauseBundle, OneFieldBundle, PrivState} 10import xiangshan.backend.fu.NewCSR.CSRConfig.{VaddrMaxWidth, XLEN} 11import xiangshan.backend.fu.NewCSR.CSRDefines.SatpMode 12import xiangshan.backend.fu.NewCSR._ 13 14 15class TrapEntryHSEventOutput extends Bundle with EventUpdatePrivStateOutput with EventOutputBase { 16 17 // Todo: use sstatus instead of mstatus 18 val mstatus = ValidIO((new MstatusBundle ).addInEvent(_.SPP, _.SPIE, _.SIE)) 19 val hstatus = ValidIO((new HstatusBundle ).addInEvent(_.SPV, _.SPVP, _.GVA)) 20 val sepc = ValidIO((new Epc ).addInEvent(_.ALL)) 21 val scause = ValidIO((new CauseBundle ).addInEvent(_.Interrupt, _.ExceptionCode)) 22 val stval = ValidIO((new OneFieldBundle).addInEvent(_.ALL)) 23 val htval = ValidIO((new OneFieldBundle).addInEvent(_.ALL)) 24 val htinst = ValidIO((new OneFieldBundle).addInEvent(_.ALL)) 25 val targetPc = ValidIO(UInt(VaddrMaxWidth.W)) 26 27 def getBundleByName(name: String): Valid[CSRBundle] = { 28 name match { 29 case "mstatus" => this.mstatus 30 case "hstatus" => this.hstatus 31 case "sepc" => this.sepc 32 case "scause" => this.scause 33 case "stval" => this.stval 34 case "htval" => this.htval 35 case "htinst" => this.htinst 36 } 37 } 38} 39 40class TrapEntryHSEventModule(implicit val p: Parameters) extends Module with CSREventBase { 41 val in = IO(new TrapEntryEventInput) 42 val out = IO(new TrapEntryHSEventOutput) 43 44 private val current = in 45 46 private val highPrioTrapNO = in.causeNO.ExceptionCode.asUInt 47 private val isException = !in.causeNO.Interrupt.asBool 48 private val isInterrupt = in.causeNO.Interrupt.asBool 49 50 private val trapPC = Wire(UInt(XLEN.W)) 51 private val trapMemVA = SignExt(in.memExceptionVAddr, XLEN) 52 private val trapMemGPA = SignExt(in.memExceptionGPAddr, XLEN) 53 private val ivmHS = !current.iMode.isModeHS && current.satp.MODE =/= SatpMode.Bare 54 private val ivmVS = !current.iMode.isModeVS && current.vsatp.MODE =/= SatpMode.Bare 55 // When enable virtual memory, the higher bit should fill with the msb of address of Sv39/Sv48/Sv57 56 trapPC := Mux(ivmHS || ivmVS, SignExt(in.trapPc, XLEN), ZeroExt(in.trapPc, XLEN)) 57 58 private val fetchIsVirt = current.iMode.isVirtual 59 private val memIsVirt = current.dMode.isVirtual 60 61 private val isFetchExcp = isException && Seq(/*EX_IAM, */ EX_IAF, EX_IPF).map(_.U === highPrioTrapNO).reduce(_ || _) 62 private val isMemExcp = isException && Seq(EX_LAM, EX_LAF, EX_SAM, EX_SAF, EX_LPF, EX_SPF).map(_.U === highPrioTrapNO).reduce(_ || _) 63 private val isBpExcp = isException && EX_BP.U === highPrioTrapNO 64 private val fetchCrossPage = in.isCrossPageIPF 65 66 private val isGuestExcp = isException && Seq(EX_IGPF, EX_LGPF, EX_SGPF).map(_.U === highPrioTrapNO).reduce(_ || _) 67 // Software breakpoint exceptions are permitted to write either 0 or the pc to xtval 68 // We fill pc here 69 private val tvalFillPc = isFetchExcp && !fetchCrossPage || isBpExcp 70 private val tvalFillPcPlus2 = isFetchExcp && fetchCrossPage 71 private val tvalFillMemVaddr = isMemExcp 72 private val tvalFillGVA = isGuestExcp || 73 (isFetchExcp || isBpExcp) && fetchIsVirt || 74 isMemExcp && memIsVirt 75 76 private val tval = Mux1H(Seq( 77 (tvalFillPc ) -> trapPC, 78 (tvalFillPcPlus2 ) -> (trapPC + 2.U), 79 (tvalFillMemVaddr && !memIsVirt ) -> trapMemVA, 80 (tvalFillMemVaddr && memIsVirt ) -> trapMemVA, 81 (isGuestExcp ) -> trapMemVA, 82 )) 83 84 private val tval2 = Mux(isGuestExcp, trapMemGPA, 0.U) 85 86 out := DontCare 87 88 out.privState.valid := valid 89 out.mstatus .valid := valid 90 out.hstatus .valid := valid 91 out.sepc .valid := valid 92 out.scause .valid := valid 93 out.stval .valid := valid 94 out.htval .valid := valid 95 out.targetPc .valid := valid 96 97 out.privState.bits := PrivState.ModeHS 98 // mstatus 99 out.mstatus.bits.SPP := current.privState.PRVM.asUInt(0, 0) // SPP is not PrivMode enum type, so asUInt and shrink the width 100 out.mstatus.bits.SPIE := current.sstatus.SIE 101 out.mstatus.bits.SIE := 0.U 102 // hstatus 103 out.hstatus.bits.SPV := current.privState.V 104 // SPVP is not PrivMode enum type, so asUInt and shrink the width 105 out.hstatus.bits.SPVP := Mux(!current.privState.isVirtual, in.hstatus.SPVP.asUInt, current.privState.PRVM.asUInt(0, 0)) 106 out.hstatus.bits.GVA := tvalFillGVA 107 out.sepc.bits.ALL := trapPC(trapPC.getWidth - 1, 1) 108 out.scause.bits.Interrupt := isInterrupt 109 out.scause.bits.ExceptionCode := highPrioTrapNO 110 out.stval.bits.ALL := tval 111 out.htval.bits.ALL := tval2 112 out.htinst.bits.ALL := 0.U 113 out.targetPc.bits := in.pcFromXtvec 114 115 dontTouch(isGuestExcp) 116 dontTouch(tvalFillGVA) 117} 118 119trait TrapEntryHSEventSinkBundle { self: CSRModule[_] => 120 val trapToHS = IO(Flipped(new TrapEntryHSEventOutput)) 121 122 private val updateBundle: ValidIO[CSRBundle] = trapToHS.getBundleByName(self.modName.toLowerCase()) 123 124 (reg.asInstanceOf[CSRBundle].getFields zip updateBundle.bits.getFields).foreach { case (sink, source) => 125 if (updateBundle.bits.eventFields.contains(source)) { 126 when(updateBundle.valid) { 127 sink := source 128 } 129 } 130 } 131} 132