qingke_rt/
lib.rs

1#![no_std]
2//! # Differences vs the riscv-rt version
3//!
4//! - The structure of exception handlers is different
5//! - The structure of core interrupt handlers is different
6//! - Hardware stack push is available, so no need to push manually
7use qingke::{
8    register::mtvec::{self, TrapMode},
9    riscv::register::mcause,
10};
11#[cfg(feature = "highcode")]
12pub use qingke_rt_macros::highcode;
13pub use qingke_rt_macros::{entry, interrupt};
14
15use core::arch::global_asm;
16
17mod asm;
18
19// Let this crate conflicts with riscv-rt
20#[unsafe(export_name = "error: riscv-rt appears more than once in the dependency graph")]
21#[doc(hidden)]
22pub static __ONCE__: () = ();
23
24unsafe extern "C" {
25    fn Exception();
26
27    fn InstructionMisaligned();
28    fn InstructionFault();
29    fn IllegalInstruction();
30    fn LoadMisaligned();
31    fn LoadFault();
32    fn StoreMisaligned();
33    fn StoreFault();
34
35    fn NonMaskableInt();
36    fn MachineEnvCall();
37    fn UserEnvCall();
38    fn Breakpoint();
39    fn SysTick();
40    fn Software();
41}
42
43#[doc(hidden)]
44#[unsafe(no_mangle)]
45#[unsafe(link_section = ".vector_table.exceptions")]
46pub static __EXCEPTIONS: [Option<unsafe extern "C" fn()>; 12] = [
47    Some(InstructionMisaligned), // 0
48    Some(InstructionFault),
49    Some(IllegalInstruction),
50    Some(Breakpoint),
51    Some(LoadMisaligned),
52    Some(LoadFault), // 5, Not accurate, async
53    Some(StoreMisaligned),
54    Some(StoreFault),  // 7, Not accurate, async
55    Some(UserEnvCall), // not available for Qingke V2
56    None,
57    None,
58    Some(MachineEnvCall),
59];
60
61#[derive(Copy, Clone, Debug, PartialEq, Eq)]
62#[repr(u8)]
63pub enum CoreInterrupt {
64    NonMaskableInt = 2,
65    Exception = 3,
66    MachineEnvCall = 5,
67    UserEnvCall = 8,
68    Breakpoint = 9,
69    SysTick = 12,
70    Software = 14,
71}
72
73impl CoreInterrupt {
74    pub fn try_from(irq: u8) -> Result<Self, u8> {
75        match irq {
76            2 => Ok(CoreInterrupt::NonMaskableInt),
77            3 => Ok(CoreInterrupt::Exception),
78            5 => Ok(CoreInterrupt::MachineEnvCall),
79            8 => Ok(CoreInterrupt::UserEnvCall),
80            9 => Ok(CoreInterrupt::Breakpoint),
81            12 => Ok(CoreInterrupt::SysTick),
82            14 => Ok(CoreInterrupt::Software),
83
84            _ => Err(irq),
85        }
86    }
87}
88
89/// Core interrupts, without the first one
90#[doc(hidden)]
91#[unsafe(no_mangle)]
92#[used]
93#[unsafe(link_section = ".vector_table.core_interrupts")]
94pub static __CORE_INTERRUPTS: [Option<unsafe extern "C" fn()>; 15] = [
95    // None, // skip 0
96    None,
97    Some(NonMaskableInt), // 2
98    Some(Exception),      // 3
99    None,
100    Some(MachineEnvCall), // 5
101    None,
102    None,
103    Some(UserEnvCall), // 8
104    Some(Breakpoint),  // 9
105    None,
106    None,
107    Some(SysTick), // 12
108    None,
109    Some(Software), // 14
110    None,
111];
112// followed by .vector_table.external_interrupts
113
114#[unsafe(link_section = ".init.rust")]
115#[unsafe(export_name = "_setup_interrupts")]
116unsafe extern "C" fn qingke_setup_interrupts() {
117    // enable hardware stack push
118    // intsyscr(0x804): Open nested interrupts and hardware stack functions
119    // 0x3 both nested interrupts and hardware stack
120    // 0x1 only hardware stack
121
122    // for user mode: mstatus = 0x80
123    // mpp(m-mode previous privilege) = 0b00 = U
124    // mpie(m-mode previous interrupt enable) = 0b1
125    // mie(m-mode interrupt enable) = 0b0
126    // interrupts will be enabled when mret at the end of handle_reset
127    // jumps to main (mret does mie = mpie)
128    // for machine mode: mstatus = 0x1880
129    // mpp = 0b11
130    // mpie = 0b1
131    // mie = 0b0
132
133    // Qingke V2A, V2C
134    // (does not have user mode)
135    #[cfg(feature = "v2")]
136    unsafe {
137        core::arch::asm!(
138            "
139            li t0, 0x1880
140            csrw mstatus, t0
141            li t0, 0x3
142            csrw 0x804, t0
143            "
144        );
145    }
146
147    // Qingke V3A
148    #[cfg(feature = "v3")]
149    unsafe {
150        #[cfg(feature = "u-mode")]
151        core::arch::asm!(
152            "
153            li t0, 0x80
154            csrs mstatus, t0
155            "
156        );
157        #[cfg(not(feature = "u-mode"))]
158        core::arch::asm!(
159            "
160            li t0, 0x1880
161            csrs mstatus, t0
162            "
163        );
164    }
165
166    // corecfgr(0xbc0): 流水线控制位 & 动态预测控制位
167    // corecfgr(0xbc0): Pipeline control bit & Dynamic prediction control
168    #[cfg(any(
169        feature = "v4",
170        not(any(feature = "v2", feature = "v3", feature = "v4"))     // Fallback condition
171    ))]
172    unsafe {
173        #[cfg(feature = "u-mode")]
174        core::arch::asm!(
175            "
176            li t0, 0x1f
177            csrw 0xbc0, t0
178            li t0, 0x3
179            csrw 0x804, t0
180            li t0, 0x80
181            csrs mstatus, t0
182            "
183        );
184        #[cfg(not(feature = "u-mode"))]
185        core::arch::asm!(
186            "
187            li t0, 0x1f
188            csrw 0xbc0, t0
189            li t0, 0x3
190            csrw 0x804, t0
191            li t0, 0x1880
192            csrs mstatus, t0
193            "
194        );
195        qingke::register::gintenr::set_enable();
196    }
197
198    // Qingke V2's mtvec must be 1KB aligned.
199
200    unsafe {
201        #[cfg(feature = "highcode")]
202        mtvec::write(0x20000000, TrapMode::VectoredAddress);
203
204        #[cfg(not(feature = "highcode"))]
205        mtvec::write(0x00000000, TrapMode::VectoredAddress);
206
207        qingke::pfic::wfi_to_wfe(true);
208    }
209}
210
211#[doc(hidden)]
212#[unsafe(no_mangle)]
213#[allow(non_snake_case)]
214pub fn DefaultInterruptHandler() {
215    loop {
216        // Prevent this from turning into a UDF instruction
217        // see rust-lang/rust#28728 for details
218        continue;
219    }
220}
221
222#[doc(hidden)]
223#[unsafe(no_mangle)]
224#[allow(non_snake_case)]
225pub fn DefaultExceptionHandler() -> ! {
226    loop {
227        // Prevent this from turning into a UDF instruction
228        // see rust-lang/rust#28728 for details
229        continue;
230    }
231}
232
233// override _start_trap in riscv-rt
234global_asm!(
235    r#"
236        .section .trap, "ax"
237        .global _exception_handler
238    _exception_handler:
239        addi sp, sp, -4
240        sw ra, 0(sp)
241        jal _exception_handler_rust
242        lw ra, 0(sp)
243        addi sp, sp, 4
244        mret
245    "#
246);
247
248#[doc(hidden)]
249#[unsafe(link_section = ".trap.rust")]
250#[unsafe(export_name = "_exception_handler_rust")]
251pub unsafe extern "C" fn qingke_exception_handler() {
252    // jump according to the __EXCEPTIONS table
253    unsafe extern "C" {
254        fn ExceptionHandler();
255    }
256
257    let cause = mcause::read();
258    let code = cause.code();
259
260    if cause.is_exception() {
261        if code < __EXCEPTIONS.len() {
262            let h = &__EXCEPTIONS[code];
263            if let Some(handler) = h {
264                unsafe { handler() };
265            } else {
266                unsafe { ExceptionHandler() };
267            }
268        } else {
269            unsafe { ExceptionHandler() };
270        }
271    } else {
272        loop {
273            // Prevent this from turning into a UDF instruction
274            // see rust-lang/rust#28728 for details
275            continue;
276        }
277    }
278}