1#[allow(clippy::upper_case_acronyms)]
2pub struct PLIC {
3 base_addr: usize,
4}
5
6#[derive(Copy, Clone)]
7pub enum IntrTargetPriority {
8 Machine = 0,
9 Supervisor = 1,
10}
11
12impl IntrTargetPriority {
13 pub fn supported_number() -> usize {
14 2
15 }
16}
17
18impl PLIC {
19 fn priority_ptr(&self, intr_source_id: usize) -> *mut u32 {
20 assert!(intr_source_id > 0 && intr_source_id <= 132);
21 (self.base_addr + intr_source_id * 4) as *mut u32
22 }
23 fn hart_id_with_priority(hart_id: usize, target_priority: IntrTargetPriority) -> usize {
24 let priority_num = IntrTargetPriority::supported_number();
25 hart_id * priority_num + target_priority as usize
26 }
27 fn enable_ptr(
28 &self,
29 hart_id: usize,
30 target_priority: IntrTargetPriority,
31 intr_source_id: usize,
32 ) -> (*mut u32, usize) {
33 let id = Self::hart_id_with_priority(hart_id, target_priority);
34 let (reg_id, reg_shift) = (intr_source_id / 32, intr_source_id % 32);
35 (
36 (self.base_addr + 0x2000 + 0x80 * id + 0x4 * reg_id) as *mut u32,
37 reg_shift,
38 )
39 }
40 fn threshold_ptr_of_hart_with_priority(
41 &self,
42 hart_id: usize,
43 target_priority: IntrTargetPriority,
44 ) -> *mut u32 {
45 let id = Self::hart_id_with_priority(hart_id, target_priority);
46 (self.base_addr + 0x20_0000 + 0x1000 * id) as *mut u32
47 }
48 fn claim_comp_ptr_of_hart_with_priority(
49 &self,
50 hart_id: usize,
51 target_priority: IntrTargetPriority,
52 ) -> *mut u32 {
53 let id = Self::hart_id_with_priority(hart_id, target_priority);
54 (self.base_addr + 0x20_0004 + 0x1000 * id) as *mut u32
55 }
56 pub unsafe fn new(base_addr: usize) -> Self {
57 Self { base_addr }
58 }
59 pub fn set_priority(&mut self, intr_source_id: usize, priority: u32) {
60 assert!(priority < 8);
61 unsafe {
62 self.priority_ptr(intr_source_id).write_volatile(priority);
63 }
64 }
65 #[allow(unused)]
66 pub fn get_priority(&mut self, intr_source_id: usize) -> u32 {
67 unsafe { self.priority_ptr(intr_source_id).read_volatile() & 7 }
68 }
69 pub fn enable(
70 &mut self,
71 hart_id: usize,
72 target_priority: IntrTargetPriority,
73 intr_source_id: usize,
74 ) {
75 let (reg_ptr, shift) = self.enable_ptr(hart_id, target_priority, intr_source_id);
76 unsafe {
77 reg_ptr.write_volatile(reg_ptr.read_volatile() | 1 << shift);
78 }
79 }
80 #[allow(unused)]
81 pub fn disable(
82 &mut self,
83 hart_id: usize,
84 target_priority: IntrTargetPriority,
85 intr_source_id: usize,
86 ) {
87 let (reg_ptr, shift) = self.enable_ptr(hart_id, target_priority, intr_source_id);
88 unsafe {
89 reg_ptr.write_volatile(reg_ptr.read_volatile() & (!(1u32 << shift)));
90 }
91 }
92 pub fn set_threshold(
93 &mut self,
94 hart_id: usize,
95 target_priority: IntrTargetPriority,
96 threshold: u32,
97 ) {
98 assert!(threshold < 8);
99 let threshold_ptr = self.threshold_ptr_of_hart_with_priority(hart_id, target_priority);
100 unsafe {
101 threshold_ptr.write_volatile(threshold);
102 }
103 }
104 #[allow(unused)]
105 pub fn get_threshold(&mut self, hart_id: usize, target_priority: IntrTargetPriority) -> u32 {
106 let threshold_ptr = self.threshold_ptr_of_hart_with_priority(hart_id, target_priority);
107 unsafe { threshold_ptr.read_volatile() & 7 }
108 }
109 pub fn claim(&mut self, hart_id: usize, target_priority: IntrTargetPriority) -> u32 {
110 let claim_comp_ptr = self.claim_comp_ptr_of_hart_with_priority(hart_id, target_priority);
111 unsafe { claim_comp_ptr.read_volatile() }
112 }
113 pub fn complete(
114 &mut self,
115 hart_id: usize,
116 target_priority: IntrTargetPriority,
117 completion: u32,
118 ) {
119 let claim_comp_ptr = self.claim_comp_ptr_of_hart_with_priority(hart_id, target_priority);
120 unsafe {
121 claim_comp_ptr.write_volatile(completion);
122 }
123 }
124}