Check whether a pending interrupt should be taken right now. Returns `Some((cause, tval, pc))` when an interrupt is ready to fire. Priority order per spec: MEI(11) > MSI(3) > MTI(7), then SEI(9) > SSI(1) > STI(5).
(&self)
| 807 | let in_s = self.regs.priv_mode == PrivilegeMode::Supervisor; |
| 808 | let mie_global = (self.csrs.mstatus >> 3) & 1; // mstatus.MIE |
| 809 | let sie_global = (self.csrs.mstatus >> 1) & 1; // mstatus.SIE |
| 810 | |
| 811 | // M-mode interrupts: not delegated to S-mode. |
| 812 | // Taken if: not in M-mode (lower modes are always preempted), or MIE=1 in M-mode. |
| 813 | let m_pending = pending & !self.csrs.mideleg; |
| 814 | if m_pending != 0 && (!in_m || mie_global == 1) { |
| 815 | let cause_idx = if m_pending & (1 << 11) != 0 { |
| 816 | 11u64 |
| 817 | } else if m_pending & (1 << 3) != 0 { |
| 818 | 3u64 |
| 819 | } else if m_pending & (1 << 7) != 0 { |
| 820 | 7u64 |
| 821 | } else { |
| 822 | m_pending.trailing_zeros() as u64 |
| 823 | }; |
| 824 | return Some(((1u64 << 63) | cause_idx, 0, self.regs.pc)); |
| 825 | } |
| 826 | |
| 827 | // S-mode interrupts: delegated; only relevant when not in M-mode. |
| 828 | let s_pending = pending & self.csrs.mideleg; |
| 829 | if s_pending != 0 && !in_m && (!in_s || sie_global == 1) { |
| 830 | let cause_idx = if s_pending & (1 << 9) != 0 { |
| 831 | 9u64 |
| 832 | } else if s_pending & (1 << 1) != 0 { |
| 833 | 1u64 |
| 834 | } else if s_pending & (1 << 5) != 0 { |
| 835 | 5u64 |
| 836 | } else { |
| 837 | s_pending.trailing_zeros() as u64 |
| 838 | }; |
| 839 | return Some(((1u64 << 63) | cause_idx, 0, self.regs.pc)); |
| 840 | } |
| 841 | |
| 842 | None |
| 843 | } |
| 844 | |
| 845 | // --- run() helper --- |
| 846 | |
| 847 | pub fn run(&mut self, bus: &mut SystemBus, max_cycles: u64) -> (TickOutcome, String) { |
| 848 | let mut outcome = TickOutcome::Continue; |
| 849 | for _ in 0..max_cycles { |
| 850 | match self.tick(bus) { |
| 851 | Ok(TickOutcome::Continue | TickOutcome::EcallSquash) => { |
| 852 | if let Some(code) = bus.take_syscon_exit() { |
| 853 | outcome = TickOutcome::Halted(code); |
| 854 | break; |
| 855 | } |