1use crate::{
2 interrupt::Trap,
3 register::{mcause, mepc, mie, mip, mstatus},
4 result::{Error, Result},
5 CoreInterruptNumber, ExceptionNumber, InterruptNumber,
6};
7
8#[derive(Copy, Clone, Debug, PartialEq, Eq)]
10#[repr(usize)]
11pub enum Interrupt {
12 SupervisorSoft = 1,
13 MachineSoft = 3,
14 SupervisorTimer = 5,
15 MachineTimer = 7,
16 SupervisorExternal = 9,
17 MachineExternal = 11,
18}
19
20unsafe impl InterruptNumber for Interrupt {
22 const MAX_INTERRUPT_NUMBER: usize = Self::MachineExternal as usize;
23
24 #[inline]
25 fn number(self) -> usize {
26 self as usize
27 }
28
29 #[inline]
30 fn from_number(value: usize) -> Result<Self> {
31 match value {
32 1 => Ok(Self::SupervisorSoft),
33 3 => Ok(Self::MachineSoft),
34 5 => Ok(Self::SupervisorTimer),
35 7 => Ok(Self::MachineTimer),
36 9 => Ok(Self::SupervisorExternal),
37 11 => Ok(Self::MachineExternal),
38 _ => Err(Error::InvalidVariant(value)),
39 }
40 }
41}
42
43unsafe impl CoreInterruptNumber for Interrupt {}
45
46#[derive(Copy, Clone, Debug, PartialEq, Eq)]
48#[repr(usize)]
49pub enum Exception {
50 InstructionMisaligned = 0,
51 InstructionFault = 1,
52 IllegalInstruction = 2,
53 Breakpoint = 3,
54 LoadMisaligned = 4,
55 LoadFault = 5,
56 StoreMisaligned = 6,
57 StoreFault = 7,
58 UserEnvCall = 8,
59 SupervisorEnvCall = 9,
60 MachineEnvCall = 11,
61 InstructionPageFault = 12,
62 LoadPageFault = 13,
63 StorePageFault = 15,
64}
65
66unsafe impl ExceptionNumber for Exception {
68 const MAX_EXCEPTION_NUMBER: usize = Self::StorePageFault as usize;
69
70 #[inline]
71 fn number(self) -> usize {
72 self as usize
73 }
74
75 #[inline]
76 fn from_number(value: usize) -> Result<Self> {
77 match value {
78 0 => Ok(Self::InstructionMisaligned),
79 1 => Ok(Self::InstructionFault),
80 2 => Ok(Self::IllegalInstruction),
81 3 => Ok(Self::Breakpoint),
82 4 => Ok(Self::LoadMisaligned),
83 5 => Ok(Self::LoadFault),
84 6 => Ok(Self::StoreMisaligned),
85 7 => Ok(Self::StoreFault),
86 8 => Ok(Self::UserEnvCall),
87 9 => Ok(Self::SupervisorEnvCall),
88 11 => Ok(Self::MachineEnvCall),
89 12 => Ok(Self::InstructionPageFault),
90 13 => Ok(Self::LoadPageFault),
91 15 => Ok(Self::StorePageFault),
92 _ => Err(Error::InvalidVariant(value)),
93 }
94 }
95}
96
97#[inline]
99pub fn is_interrupt_enabled<I: CoreInterruptNumber>(interrupt: I) -> bool {
100 mie::read().is_enabled(interrupt)
101}
102
103#[inline]
105pub fn disable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
106 mie::disable(interrupt);
107}
108
109#[inline]
120pub unsafe fn enable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
121 mie::enable(interrupt);
122}
123
124#[inline]
126pub fn is_interrupt_pending<I: CoreInterruptNumber>(interrupt: I) -> bool {
127 mip::read().is_pending(interrupt)
128}
129
130#[inline]
132pub fn disable() {
133 unsafe { mstatus::clear_mie() }
135}
136
137#[inline]
149pub unsafe fn enable() {
150 mstatus::set_mie()
151}
152
153#[inline]
158pub fn try_cause<I: CoreInterruptNumber, E: ExceptionNumber>() -> Result<Trap<I, E>> {
159 mcause::read().cause().try_into()
160}
161
162#[inline]
167pub fn cause<I: CoreInterruptNumber, E: ExceptionNumber>() -> Trap<I, E> {
168 try_cause().unwrap()
169}
170
171#[inline]
180pub fn free<F, R>(f: F) -> R
181where
182 F: FnOnce() -> R,
183{
184 let mstatus = mstatus::read();
185
186 disable();
188
189 let r = f();
190
191 if mstatus.mie() {
194 unsafe { enable() };
195 }
196
197 r
198}
199
200#[inline]
213pub unsafe fn nested<F, R>(f: F) -> R
214where
215 F: FnOnce() -> R,
216{
217 let mstatus = mstatus::read();
218 let mepc = mepc::read();
219
220 enable();
222
223 let r = f();
224
225 if !mstatus.mie() {
228 disable();
229 }
230
231 if mstatus.mpie() {
233 mstatus::set_mpie();
234 }
235 mstatus::set_mpp(mstatus.mpp());
236 mepc::write(mepc);
237
238 r
239}
240
241#[cfg(test)]
242mod test {
243 use super::*;
244 use Exception::*;
245 use Interrupt::*;
246
247 #[test]
248 fn test_interrupt() {
249 assert_eq!(Interrupt::from_number(1), Ok(SupervisorSoft));
250 assert_eq!(Interrupt::from_number(2), Err(Error::InvalidVariant(2)));
251 assert_eq!(Interrupt::from_number(3), Ok(MachineSoft));
252 assert_eq!(Interrupt::from_number(4), Err(Error::InvalidVariant(4)));
253 assert_eq!(Interrupt::from_number(5), Ok(SupervisorTimer));
254 assert_eq!(Interrupt::from_number(6), Err(Error::InvalidVariant(6)));
255 assert_eq!(Interrupt::from_number(7), Ok(MachineTimer));
256 assert_eq!(Interrupt::from_number(8), Err(Error::InvalidVariant(8)));
257 assert_eq!(Interrupt::from_number(9), Ok(SupervisorExternal));
258 assert_eq!(Interrupt::from_number(10), Err(Error::InvalidVariant(10)));
259 assert_eq!(Interrupt::from_number(11), Ok(MachineExternal));
260 assert_eq!(Interrupt::from_number(12), Err(Error::InvalidVariant(12)));
261
262 assert_eq!(SupervisorSoft.number(), 1);
263 assert_eq!(MachineSoft.number(), 3);
264 assert_eq!(SupervisorTimer.number(), 5);
265 assert_eq!(MachineTimer.number(), 7);
266 assert_eq!(SupervisorExternal.number(), 9);
267 assert_eq!(MachineExternal.number(), 11);
268
269 assert_eq!(MachineExternal.number(), Interrupt::MAX_INTERRUPT_NUMBER)
270 }
271
272 #[test]
273 fn test_exception() {
274 assert_eq!(Exception::from_number(0), Ok(InstructionMisaligned));
275 assert_eq!(Exception::from_number(1), Ok(InstructionFault));
276 assert_eq!(Exception::from_number(2), Ok(IllegalInstruction));
277 assert_eq!(Exception::from_number(3), Ok(Breakpoint));
278 assert_eq!(Exception::from_number(4), Ok(LoadMisaligned));
279 assert_eq!(Exception::from_number(5), Ok(LoadFault));
280 assert_eq!(Exception::from_number(6), Ok(StoreMisaligned));
281 assert_eq!(Exception::from_number(7), Ok(StoreFault));
282 assert_eq!(Exception::from_number(8), Ok(UserEnvCall));
283 assert_eq!(Exception::from_number(9), Ok(SupervisorEnvCall));
284 assert_eq!(Exception::from_number(10), Err(Error::InvalidVariant(10)));
285 assert_eq!(Exception::from_number(11), Ok(MachineEnvCall));
286 assert_eq!(Exception::from_number(12), Ok(InstructionPageFault));
287 assert_eq!(Exception::from_number(13), Ok(LoadPageFault));
288 assert_eq!(Exception::from_number(14), Err(Error::InvalidVariant(14)));
289 assert_eq!(Exception::from_number(15), Ok(StorePageFault));
290 assert_eq!(Exception::from_number(16), Err(Error::InvalidVariant(16)));
291
292 assert_eq!(InstructionMisaligned.number(), 0);
293 assert_eq!(InstructionFault.number(), 1);
294 assert_eq!(IllegalInstruction.number(), 2);
295 assert_eq!(Breakpoint.number(), 3);
296 assert_eq!(LoadMisaligned.number(), 4);
297 assert_eq!(LoadFault.number(), 5);
298 assert_eq!(StoreMisaligned.number(), 6);
299 assert_eq!(StoreFault.number(), 7);
300 assert_eq!(UserEnvCall.number(), 8);
301 assert_eq!(SupervisorEnvCall.number(), 9);
302 assert_eq!(MachineEnvCall.number(), 11);
303 assert_eq!(InstructionPageFault.number(), 12);
304 assert_eq!(LoadPageFault.number(), 13);
305 assert_eq!(StorePageFault.number(), 15);
306
307 assert_eq!(StorePageFault.number(), Exception::MAX_EXCEPTION_NUMBER)
308 }
309}