#![no_std]

use core::panic::PanicInfo;
use core::ptr;

// The reset handler
#[no_mangle]
pub unsafe extern "C" fn Reset() -> ! {
    // Initialise RAM
    extern "C" {
        static mut _sbss: u8;
        static mut _ebss: u8;

        static mut _sdata: u8;
        static mut _edata: u8;
        static _sidata: u8;
    }

    let count = &_ebss as *const u8 as usize - &_sbss as *const u8 as usize;
    ptr::write_bytes(&mut _sbss as *mut u8, 0, count);

    let count = &_edata as *const u8 as usize - &_sdata as *const u8 as usize;
    ptr::copy_nonoverlapping(&_sidata as *const u8, &mut _sdata as *mut u8, count);

    // Call user entry point
    extern "Rust" {
        fn main() -> !;
    }

    main()
}

// The reset vector, a pointer to into the RESET handler
#[link_section = ".vector_table.reset_vector"]
#[no_mangle]
pub static RESET_VECTOR: unsafe extern "C" fn() -> !  = Reset;

#[panic_handler]
fn panic(_panic: &PanicInfo<'_>) -> ! {
    loop {}
}

#[macro_export]
macro_rules! entry {
    ($path:path) => {
        #[export_name = "main"]
        pub unsafe fn __main() -> ! {
            // type check given path
            let f: fn() -> ! = $path;
            f()
        }
    }
}

pub union Vector {
    reserved: u32,
    handler: unsafe extern "C" fn(),
}

extern "C" {
    fn NMI();
    fn HardFault();
    fn MemManage();
    fn BusFault();
    fn UsageFault();
    fn SVCall();
    fn PendSV();
    fn SysTick();
}

#[link_section = ".vector_table.exceptions"]
#[no_mangle]
pub static EXCEPTIONS: [Vector; 14] = [
    Vector { handler: NMI },
    Vector { handler: HardFault },
    Vector { handler: MemManage },
    Vector { handler: BusFault },
    Vector { handler: UsageFault },
    /* Some entries are reserved, according to ARM documentation they are 
     * set to value 0*/
    Vector { reserved: 0},
    Vector { reserved: 0},
    Vector { reserved: 0},
    Vector { reserved: 0},
    Vector { handler: SVCall },
    Vector { reserved: 0},
    Vector { reserved: 0},
    Vector { handler: PendSV },
    Vector { handler: SysTick },
];

// Default Exception handler
#[no_mangle]
pub extern "C" fn DefaultExceptionHandler() {
    loop {}
} 
