riscv/csr/
mcause.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

use kernel::utilities::registers::{register_bitfields, LocalRegisterCopy};

register_bitfields![usize,
    pub mcause [
        is_interrupt OFFSET(crate::XLEN - 1) NUMBITS(1) [],
        reason OFFSET(0) NUMBITS(crate::XLEN - 1) []
    ],
    // Per the spec, implementations are allowed to use the higher bits of the
    // interrupt/exception reason for their own purposes.  For regular parsing,
    // we only concern ourselves with the "standard" values.
    reason [
        reserved OFFSET(4) NUMBITS(crate::XLEN - 5) [],
        std OFFSET(0) NUMBITS(4) []
    ]
];

/// Trap Cause
#[derive(Copy, Clone, Debug)]
pub enum Trap {
    Interrupt(Interrupt),
    Exception(Exception),
}

impl From<LocalRegisterCopy<usize, mcause::Register>> for Trap {
    fn from(val: LocalRegisterCopy<usize, mcause::Register>) -> Self {
        if val.is_set(mcause::is_interrupt) {
            Trap::Interrupt(Interrupt::from_reason(val.read(mcause::reason)))
        } else {
            Trap::Exception(Exception::from_reason(val.read(mcause::reason)))
        }
    }
}

impl From<usize> for Trap {
    fn from(csr_val: usize) -> Self {
        Self::from(LocalRegisterCopy::<usize, mcause::Register>::new(csr_val))
    }
}

/// Interrupt
#[derive(Copy, Clone, Debug)]
pub enum Interrupt {
    UserSoft,
    SupervisorSoft,
    MachineSoft,
    UserTimer,
    SupervisorTimer,
    MachineTimer,
    UserExternal,
    SupervisorExternal,
    MachineExternal,
    Unknown,
}

/// Exception
#[derive(Copy, Clone, Debug)]
pub enum Exception {
    InstructionMisaligned,
    InstructionFault,
    IllegalInstruction,
    Breakpoint,
    LoadMisaligned,
    LoadFault,
    StoreMisaligned,
    StoreFault,
    UserEnvCall,
    SupervisorEnvCall,
    MachineEnvCall,
    InstructionPageFault,
    LoadPageFault,
    StorePageFault,
    Unknown,
}

impl Interrupt {
    fn from_reason(val: usize) -> Self {
        let reason = LocalRegisterCopy::<usize, reason::Register>::new(val);
        match reason.read(reason::std) {
            0 => Interrupt::UserSoft,
            1 => Interrupt::SupervisorSoft,
            3 => Interrupt::MachineSoft,
            4 => Interrupt::UserTimer,
            5 => Interrupt::SupervisorTimer,
            7 => Interrupt::MachineTimer,
            8 => Interrupt::UserExternal,
            9 => Interrupt::SupervisorExternal,
            11 => Interrupt::MachineExternal,
            _ => Interrupt::Unknown,
        }
    }
}

impl Exception {
    fn from_reason(val: usize) -> Self {
        let reason = LocalRegisterCopy::<usize, reason::Register>::new(val);
        match reason.read(reason::std) {
            0 => Exception::InstructionMisaligned,
            1 => Exception::InstructionFault,
            2 => Exception::IllegalInstruction,
            3 => Exception::Breakpoint,
            4 => Exception::LoadMisaligned,
            5 => Exception::LoadFault,
            6 => Exception::StoreMisaligned,
            7 => Exception::StoreFault,
            8 => Exception::UserEnvCall,
            9 => Exception::SupervisorEnvCall,
            11 => Exception::MachineEnvCall,
            12 => Exception::InstructionPageFault,
            13 => Exception::LoadPageFault,
            15 => Exception::StorePageFault,
            _ => Exception::Unknown,
        }
    }
}