#![no_std]
#![allow(unexpected_cfgs)]
use qingke::{
register::mtvec::{self, TrapMode},
riscv::register::mcause,
};
#[cfg(feature = "highcode")]
pub use qingke_rt_macros::highcode;
pub use qingke_rt_macros::{entry, interrupt};
use core::arch::global_asm;
mod asm;
#[unsafe(export_name = "error: riscv-rt appears more than once in the dependency graph")]
#[doc(hidden)]
pub static __ONCE__: () = ();
unsafe extern "C" {
fn Exception();
fn InstructionMisaligned();
fn InstructionFault();
fn IllegalInstruction();
fn LoadMisaligned();
fn LoadFault();
fn StoreMisaligned();
fn StoreFault();
fn NonMaskableInt();
fn MachineEnvCall();
fn UserEnvCall();
fn Breakpoint();
fn SysTick();
fn Software();
}
#[doc(hidden)]
#[unsafe(no_mangle)]
#[unsafe(link_section = ".vector_table.exceptions")]
pub static __EXCEPTIONS: [Option<unsafe extern "C" fn()>; 12] = [
Some(InstructionMisaligned), Some(InstructionFault),
Some(IllegalInstruction),
Some(Breakpoint),
Some(LoadMisaligned),
Some(LoadFault), Some(StoreMisaligned),
Some(StoreFault), Some(UserEnvCall), None,
None,
Some(MachineEnvCall),
];
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum CoreInterrupt {
NonMaskableInt = 2,
Exception = 3,
MachineEnvCall = 5,
UserEnvCall = 8,
Breakpoint = 9,
SysTick = 12,
Software = 14,
}
impl CoreInterrupt {
pub fn try_from(irq: u8) -> Result<Self, u8> {
match irq {
2 => Ok(CoreInterrupt::NonMaskableInt),
3 => Ok(CoreInterrupt::Exception),
5 => Ok(CoreInterrupt::MachineEnvCall),
8 => Ok(CoreInterrupt::UserEnvCall),
9 => Ok(CoreInterrupt::Breakpoint),
12 => Ok(CoreInterrupt::SysTick),
14 => Ok(CoreInterrupt::Software),
_ => Err(irq),
}
}
}
#[doc(hidden)]
#[unsafe(no_mangle)]
#[used]
#[unsafe(link_section = ".vector_table.core_interrupts")]
pub static __CORE_INTERRUPTS: [Option<unsafe extern "C" fn()>; 15] = [
None,
Some(NonMaskableInt), Some(Exception), None,
Some(MachineEnvCall), None,
None,
Some(UserEnvCall), Some(Breakpoint), None,
None,
Some(SysTick), None,
Some(Software), None,
];
#[unsafe(link_section = ".init.rust")]
#[unsafe(export_name = "_setup_interrupts")]
unsafe extern "C" fn qingke_setup_interrupts() {
#[cfg(qingke_v2)]
unsafe {
core::arch::asm!(
"
li t0, 0x1880
csrw mstatus, t0
li t0, 0x3
csrw 0x804, t0
"
);
}
#[cfg(all(qingke_v3, not(feature = "v3f")))]
unsafe {
#[cfg(feature = "u-mode")]
core::arch::asm!(
"
li t0, 0x80
csrs mstatus, t0
"
);
#[cfg(not(feature = "u-mode"))]
core::arch::asm!(
"
li t0, 0x1880
csrs mstatus, t0
"
);
}
#[cfg(feature = "v3f")]
unsafe {
use qingke::register::inestcr::{self, NestLevel};
inestcr::write(NestLevel::Two as usize);
core::arch::asm!(
"
li t0, 0x123703E1
csrw 0xBC0, t0
li t0, 0x07
csrw 0x804, t0
li t0, 0x6088
csrw mstatus, t0
"
);
}
#[cfg(feature = "v5f")]
unsafe {
use qingke::register::inestcr::{self, NestLevel};
inestcr::write(NestLevel::Eight as usize);
core::arch::asm!(
"
li t0, 0x1237B3E0
csrw 0xBC0, t0
li t0, 0x0F
csrw 0x804, t0
li t0, 0x6088
csrw mstatus, t0
"
);
}
#[cfg(any(
qingke_v4,
not(any(qingke_v2, qingke_v3, qingke_v4, qingke_v5)) // Fallback when no leaf is selected
))]
unsafe {
#[cfg(feature = "u-mode")]
core::arch::asm!(
"
li t0, 0x1f
csrw 0xbc0, t0
li t0, 0x3
csrw 0x804, t0
li t0, 0x80
csrs mstatus, t0
"
);
#[cfg(not(feature = "u-mode"))]
core::arch::asm!(
"
li t0, 0x1f
csrw 0xbc0, t0
li t0, 0x3
csrw 0x804, t0
li t0, 0x1880
csrs mstatus, t0
"
);
qingke::register::gintenr::set_enable();
}
#[cfg(feature = "v3a")]
unsafe {
unsafe extern "C" {
fn _unified_trap_handler();
}
mtvec::write(_unified_trap_handler as *const () as usize, TrapMode::Direct);
}
#[cfg(not(feature = "v3a"))]
unsafe {
#[cfg(feature = "highcode")]
{
unsafe extern "C" {
static _highcode_vma_start: u8;
}
mtvec::write(
&raw const _highcode_vma_start as usize,
TrapMode::VectoredAddress,
);
}
#[cfg(not(feature = "highcode"))]
{
unsafe extern "C" {
static _start: u8;
}
mtvec::write(&raw const _start as usize, TrapMode::VectoredAddress);
}
}
unsafe {
qingke::pfic::wfi_to_wfe(true);
}
}
#[doc(hidden)]
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub fn DefaultInterruptHandler() {
loop {
continue;
}
}
#[doc(hidden)]
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
pub fn DefaultExceptionHandler() -> ! {
loop {
continue;
}
}
global_asm!(
r#"
.section .trap, "ax"
.global _exception_handler
_exception_handler:
addi sp, sp, -4
sw ra, 0(sp)
jal _exception_handler_rust
lw ra, 0(sp)
addi sp, sp, 4
mret
"#
);
#[cfg(all(feature = "v3a", feature = "highcode"))]
global_asm!(
r#"
.section .trap, "ax"
.global _unified_trap_handler
.align 2
_unified_trap_handler:
csrr t0, mcause
bgez t0, _exception_handler
slli t0, t0, 1
srli t0, t0, 1
slli t0, t0, 2
la t1, _highcode_vma_start
add t0, t0, t1
lw t0, 0(t0)
beqz t0, 1f
jr t0
1:
la t0, DefaultInterruptHandler
jr t0
"#
);
#[cfg(all(feature = "v3a", not(feature = "highcode")))]
global_asm!(
r#"
.section .trap, "ax"
.global _unified_trap_handler
.align 2
_unified_trap_handler:
csrr t0, mcause
bgez t0, _exception_handler
slli t0, t0, 1
srli t0, t0, 1
slli t0, t0, 2
la t1, _start
add t0, t0, t1
lw t0, 0(t0)
beqz t0, 1f
jr t0
1:
j DefaultInterruptHandler
"#
);
#[doc(hidden)]
#[unsafe(link_section = ".trap.rust")]
#[unsafe(export_name = "_exception_handler_rust")]
pub unsafe extern "C" fn qingke_exception_handler() {
unsafe extern "C" {
fn ExceptionHandler();
}
let cause = mcause::read();
let code = cause.code();
if cause.is_exception() {
if code < __EXCEPTIONS.len() {
let h = &__EXCEPTIONS[code];
if let Some(handler) = h {
unsafe { handler() };
} else {
unsafe { ExceptionHandler() };
}
} else {
unsafe { ExceptionHandler() };
}
} else {
loop {
continue;
}
}
}