register handler asm("csrw mtvec, %0" ::"r"(handler)); --- helper functions #define CLINT0_MTIME 0x200bff8 #define CLINT0_MTIMECMP 0x2004000 long long mtime_get() { int low = *(int*)(CLINT0_MTIME); int high = *(int*)(CLINT0_MTIME + 4); return (((long long)high) << 32) | low; } void mtimecmp_set(long long time) { *(int*)(CLINT0_MTIMECMP + 0) = (int)time; *(int*)(CLINT0_MTIMECMP + 4) = (int)(time >> 32); } --- set timer mtimecmp_set(mtime_get() + QUANTUM); --- enable timer interrupt int mstatus, mie; asm("csrr %0, mstatus" : "=r"(mstatus)); asm("csrw mstatus, %0" ::"r"(mstatus | 0x8)); asm("csrr %0, mie" : "=r"(mie)); asm("csrw mie, %0" ::"r"(mie | 0x80)); --- resilient to timer overflow long long mtime_get() { int low, high; do { high = *(int*)(CLINT0_MTIME + 4); low = *(int*)(CLINT0_MTIME); } while ( *(int*)(CLINT0_MTIME + 4) != high ); return (((long long)high) << 32) | low; } void mtimecmp_set(long long time) { *(int*)(CLINT0_MTIMECMP + 4) = 0xFFFFFFFF; *(int*)(CLINT0_MTIMECMP + 0) = (int)time; *(int*)(CLINT0_MTIMECMP + 4) = (int)(time >> 32); } --- See which interrupts int mcause; asm("csrr %0,mcause" : "=r"(mcause)); printf("cause: %d\n", mcause);