forked from vherdt/riscv-vp
-
Notifications
You must be signed in to change notification settings - Fork 50
/
Copy pathirq.c
72 lines (50 loc) · 2.01 KB
/
irq.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include "irq.h"
#include "assert.h"
#define RISCV_MACHINE_SOFTWARE_INTERRUPT 3
#define RISCV_MACHINE_TIMER_INTERRUPT 7
#define RISCV_MACHINE_EXTERNAL_INTERRUPT 11
#define PLIC_BASE 0x40000000
#define IRQ_TABLE_NUM_ENTRIES 64
static volatile uint32_t * const PLIC_INTERRUPT_ENABLE_START = (uint32_t * const)(PLIC_BASE + 0x2000);
static volatile uint32_t * const PLIC_CLAIM_AND_RESPONSE_REGISTER = (uint32_t * const)(PLIC_BASE + 0x200004);
static void irq_empty_handler() {}
static irq_handler_t irq_handler_table[IRQ_TABLE_NUM_ENTRIES] = { [ 0 ... IRQ_TABLE_NUM_ENTRIES-1 ] = irq_empty_handler };
#define CLINT_BASE 0x2000000
volatile uint64_t* mtime = (uint64_t*)(CLINT_BASE + 0xbff8);
volatile uint64_t* mtimecmp = (uint64_t*)(CLINT_BASE + 0x4000);
static irq_handler_t timer_irq_handler = 0;
void level_1_interrupt_handler(uint32_t cause) {
switch (cause & 0xf) {
case RISCV_MACHINE_EXTERNAL_INTERRUPT: {
asm volatile ("csrc mip, %0" : : "r" (0x800));
uint32_t irq_id = *PLIC_CLAIM_AND_RESPONSE_REGISTER;
irq_handler_table[irq_id]();
*PLIC_CLAIM_AND_RESPONSE_REGISTER = 1;
return;
}
case RISCV_MACHINE_TIMER_INTERRUPT: {
// Note: the pending timer interrupt bit will be automatically cleared when writing to the *mtimecmp* register of this hart
if (timer_irq_handler) {
// let the user registered handler clear the timer interrupt bit
timer_irq_handler();
} else {
// reset the *mtimecmp* register to zero to clear the pending bit
*mtimecmp = 0;
}
return;
}
}
assert (0 && "unsupported cause");
}
void register_interrupt_handler(uint32_t irq_id, irq_handler_t fn) {
assert (irq_id < IRQ_TABLE_NUM_ENTRIES);
// enable interrupt
volatile uint32_t* const reg = (PLIC_INTERRUPT_ENABLE_START + irq_id/32);
*reg |= 1 << (irq_id%32);
// set a prio different to zero (which means do-not-interrupt)
*((uint32_t*) (PLIC_BASE + irq_id*sizeof(uint32_t))) = 1;
irq_handler_table[irq_id] = fn;
}
void register_timer_interrupt_handler(irq_handler_t fn) {
timer_irq_handler = fn;
}