1#![no_std]
5#![feature(naked_functions)]
6#![deny(warnings)]
7
8use core::{arch::naked_asm, cell::UnsafeCell};
9
10#[repr(transparent)]
12pub struct MTIME(UnsafeCell<u64>);
13
14#[repr(transparent)]
16pub struct MTIMECMP(UnsafeCell<u64>);
17
18#[repr(transparent)]
20pub struct MSIP(UnsafeCell<u32>);
21
22#[repr(transparent)]
24pub struct SETSSIP(UnsafeCell<u32>);
25
26#[repr(transparent)]
28pub struct MTIMER([MTIMECMP; 4095]);
29
30#[repr(transparent)]
32pub struct MSWI([MSIP; 4095]);
33
34#[repr(transparent)]
36pub struct SSWI([SETSSIP; 4095]);
37
38#[repr(C)]
40pub struct SifiveClint {
41 mswi: MSWI,
42 reserve: u32,
43 mtimer: MTIMER,
44 mtime: MTIME,
45}
46
47impl SifiveClint {
48 const MTIMER_OFFSET: usize = size_of::<MSWI>() + size_of::<u32>();
49 const MTIME_OFFSET: usize = Self::MTIMER_OFFSET + size_of::<MTIMER>();
50
51 #[inline]
52 pub fn read_mtime(&self) -> u64 {
53 unsafe { self.mtime.0.get().read_volatile() }
54 }
55
56 #[inline]
57 pub fn write_mtime(&self, val: u64) {
58 unsafe { self.mtime.0.get().write_volatile(val) }
59 }
60
61 #[inline]
62 pub fn read_mtimecmp(&self, hart_idx: usize) -> u64 {
63 unsafe { self.mtimer.0[hart_idx].0.get().read_volatile() }
64 }
65
66 #[inline]
67 pub fn write_mtimecmp(&self, hart_idx: usize, val: u64) {
68 unsafe { self.mtimer.0[hart_idx].0.get().write_volatile(val) }
69 }
70
71 #[inline]
72 pub fn read_msip(&self, hart_idx: usize) -> bool {
73 unsafe { self.mswi.0[hart_idx].0.get().read_volatile() != 0 }
74 }
75
76 #[inline]
77 pub fn set_msip(&self, hart_idx: usize) {
78 unsafe { self.mswi.0[hart_idx].0.get().write_volatile(1) }
79 }
80
81 #[inline]
82 pub fn clear_msip(&self, hart_idx: usize) {
83 unsafe { self.mswi.0[hart_idx].0.get().write_volatile(0) }
84 }
85}
86
87impl SifiveClint {
88 #[naked]
89 pub extern "C" fn read_mtime_naked(&self) -> u64 {
90 unsafe {
91 naked_asm!(
92 " addi sp, sp, -8
93 sd a1, (sp)
94
95 li a1, {offset}
96 add a0, a0, a1
97
98 ld a1, (sp)
99 addi sp, sp, 8
100
101 ld a0, (a0)
102 ret
103 ",
104 offset = const Self::MTIME_OFFSET,
105 )
106 }
107 }
108
109 #[naked]
110 pub extern "C" fn write_mtime_naked(&self, val: u64) -> u64 {
111 unsafe {
112 naked_asm!(
113 " addi sp, sp, -8
114 sd a1, (sp)
115
116 li a1, {offset}
117 add a0, a0, a1
118
119 ld a1, (sp)
120 addi sp, sp, 8
121
122 sd a1, (a0)
123 ret
124 ",
125 offset = const Self::MTIME_OFFSET,
126 )
127 }
128 }
129
130 #[naked]
131 pub extern "C" fn read_mtimecmp_naked(&self, hart_idx: usize) -> u64 {
132 unsafe {
133 naked_asm!(
134 " slli a1, a1, 3
135 add a0, a0, a1
136
137 li a1, {offset}
138 add a0, a0, a1
139
140 ld a0, (a0)
141 ret
142 ",
143 offset = const Self::MTIMER_OFFSET,
144 )
145 }
146 }
147
148 #[naked]
149 pub extern "C" fn write_mtimecmp_naked(&self, hart_idx: usize, val: u64) {
150 unsafe {
151 naked_asm!(
152 " slli a1, a1, 3
153 add a0, a0, a1
154
155 li a1, {offset}
156 add a0, a0, a1
157
158 sd a2, (a0)
159 ret
160 ",
161 offset = const Self::MTIMER_OFFSET,
162 )
163 }
164 }
165
166 #[naked]
167 pub extern "C" fn read_msip_naked(&self, hart_idx: usize) -> bool {
168 unsafe {
169 naked_asm!(
170 " slli a1, a1, 2
171 add a0, a0, a1
172 lw a0, (a0)
173 ret
174 ",
175 )
176 }
177 }
178
179 #[naked]
180 pub extern "C" fn set_msip_naked(&self, hart_idx: usize) {
181 unsafe {
182 naked_asm!(
183 " slli a1, a1, 2
184 add a0, a0, a1
185 addi a1, zero, 1
186 sw a1, (a0)
187 ret
188 ",
189 )
190 }
191 }
192
193 #[naked]
194 pub extern "C" fn clear_msip_naked(&self, hart_idx: usize) {
195 unsafe {
196 naked_asm!(
197 " slli a1, a1, 2
198 add a0, a0, a1
199 sw zero, (a0)
200 ret
201 ",
202 )
203 }
204 }
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210 #[test]
211 fn test() {
212 assert_eq!(size_of::<MSWI>(), 0x3ffc);
213 assert_eq!(size_of::<SSWI>(), 0x3ffc);
214 assert_eq!(size_of::<MTIMER>(), 0x7ff8);
215 assert_eq!(size_of::<SifiveClint>(), 0xc000);
216 }
217}