ab_riscv_primitives/registers/
machine.rs1use crate::registers::general_purpose::{RegType, Register};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8#[repr(u16)]
9pub enum MCsr {
10 Mvendorid = 0xF11,
12 Marchid = 0xF12,
14 Mimpid = 0xF13,
16 Mhartid = 0xF14,
18
19 Mstatus = 0x300,
21 Misa = 0x301,
23 Mie = 0x304,
25 Mtvec = 0x305,
27
28 Mscratch = 0x340,
30 Mepc = 0x341,
32 Mcause = 0x342,
34 Mtval = 0x343,
36 Mip = 0x344,
38}
39
40impl MCsr {
41 #[inline(always)]
43 pub const fn from_index(index: u16) -> Option<Self> {
44 match index {
45 0xF11 => Some(Self::Mvendorid),
46 0xF12 => Some(Self::Marchid),
47 0xF13 => Some(Self::Mimpid),
48 0xF14 => Some(Self::Mhartid),
49 0x300 => Some(Self::Mstatus),
50 0x301 => Some(Self::Misa),
51 0x304 => Some(Self::Mie),
52 0x305 => Some(Self::Mtvec),
53 0x340 => Some(Self::Mscratch),
54 0x341 => Some(Self::Mepc),
55 0x342 => Some(Self::Mcause),
56 0x343 => Some(Self::Mtval),
57 0x344 => Some(Self::Mip),
58 _ => None,
59 }
60 }
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65#[repr(u32)]
66pub enum MCauseException {
67 InstructionAddressMisaligned = 0,
69 InstructionAccessFault = 1,
71 IllegalInstruction = 2,
73 Breakpoint = 3,
75 LoadAddressMisaligned = 4,
77 LoadAccessFault = 5,
79 StoreAddressMisaligned = 6,
81 StoreAccessFault = 7,
83 UserEnvironmentCall = 8,
85 SupervisorEnvironmentCall = 9,
87 MachineEnvironmentCall = 11,
89 InstructionPageFault = 12,
91 LoadPageFault = 13,
93 StorePageFault = 15,
95}
96
97impl MCauseException {
98 #[inline(always)]
101 pub const fn from_code(code: u64) -> Option<Self> {
102 match code {
103 0 => Some(Self::InstructionAddressMisaligned),
104 1 => Some(Self::InstructionAccessFault),
105 2 => Some(Self::IllegalInstruction),
106 3 => Some(Self::Breakpoint),
107 4 => Some(Self::LoadAddressMisaligned),
108 5 => Some(Self::LoadAccessFault),
109 6 => Some(Self::StoreAddressMisaligned),
110 7 => Some(Self::StoreAccessFault),
111 8 => Some(Self::UserEnvironmentCall),
112 9 => Some(Self::SupervisorEnvironmentCall),
113 11 => Some(Self::MachineEnvironmentCall),
114 12 => Some(Self::InstructionPageFault),
115 13 => Some(Self::LoadPageFault),
116 15 => Some(Self::StorePageFault),
117 _ => None,
118 }
119 }
120
121 #[inline(always)]
123 pub const fn to_raw<Reg>(self) -> Reg::Type
124 where
125 Reg: [const] Register,
126 {
127 Reg::Type::from(self as u32)
128 }
129}
130
131#[derive(Debug, Clone, Copy, PartialEq, Eq)]
133#[repr(u32)]
134pub enum MCauseInterrupt {
135 UserSoftware = 0,
137 SupervisorSoftware = 1,
139 MachineSoftware = 3,
141 UserTimer = 4,
143 SupervisorTimer = 5,
145 MachineTimer = 7,
147 UserExternal = 8,
149 SupervisorExternal = 9,
151 MachineExternal = 11,
153}
154
155impl MCauseInterrupt {
156 #[inline(always)]
159 pub const fn from_code(code: u64) -> Option<Self> {
160 match code {
161 0 => Some(Self::UserSoftware),
162 1 => Some(Self::SupervisorSoftware),
163 3 => Some(Self::MachineSoftware),
164 4 => Some(Self::UserTimer),
165 5 => Some(Self::SupervisorTimer),
166 7 => Some(Self::MachineTimer),
167 8 => Some(Self::UserExternal),
168 9 => Some(Self::SupervisorExternal),
169 11 => Some(Self::MachineExternal),
170 _ => None,
171 }
172 }
173
174 #[inline(always)]
176 pub const fn to_raw<Reg>(self) -> Reg::Type
177 where
178 Reg: [const] Register,
179 {
180 Reg::Type::from(self as u32) | (Reg::Type::from(1u8) << (Reg::XLEN - 1))
181 }
182}
183
184#[derive(Debug, Clone, Copy, PartialEq, Eq)]
186pub enum MCause {
187 Exception(MCauseException),
188 Interrupt(MCauseInterrupt),
189}
190
191impl From<MCauseException> for MCause {
192 #[inline(always)]
193 fn from(cause: MCauseException) -> Self {
194 Self::Exception(cause)
195 }
196}
197
198impl From<MCauseInterrupt> for MCause {
199 #[inline(always)]
200 fn from(cause: MCauseInterrupt) -> Self {
201 Self::Interrupt(cause)
202 }
203}
204
205impl MCause {
206 #[inline(always)]
208 pub const fn from_raw<Reg>(raw: Reg::Type) -> Option<Self>
209 where
210 Reg: [const] Register,
211 {
212 let raw = raw.as_u64();
213 let is_interrupt = (raw & (1u64 << (Reg::XLEN - 1))) != 0;
214 let code = raw & !(1u64 << (Reg::XLEN - 1));
215
216 if is_interrupt {
217 MCauseInterrupt::from_code(code).map(Self::Interrupt)
218 } else {
219 MCauseException::from_code(code).map(Self::Exception)
220 }
221 }
222
223 #[inline(always)]
225 pub const fn to_raw<Reg>(self) -> Reg::Type
226 where
227 Reg: [const] Register,
228 {
229 match self {
230 MCause::Exception(exception) => exception.to_raw::<Reg>(),
231 MCause::Interrupt(interrupt) => interrupt.to_raw::<Reg>(),
232 }
233 }
234}