1pub mod encoding;
6
7use core::marker::PhantomData;
8
9use crate::{Accessible, IoHandle, LayoutOver, Register, Ro, RwSafe, RwUnsafe, WoSafe, WoUnsafe};
10
11pub type Csr<Encoding, Layout> =
26 Register<Layout, <Encoding as ControlAndStatusRegisterEncoding>::Access, CsrIo<Encoding>>;
27
28pub trait ControlAndStatusRegisterEncoding {
30 const VALUE: u16;
32
33 type Access: Accessible;
35
36 const VALID: ();
38}
39
40pub struct CsrEncoding<const ENCODING: u16, Access: Accessible>(PhantomData<Access>);
42
43macro_rules! impl_csr_encoding {
44 ($access:ty, $validate:block) => {
45 impl<const ENCODING: u16> ControlAndStatusRegisterEncoding
46 for CsrEncoding<ENCODING, $access>
47 {
48 const VALUE: u16 = ENCODING;
49 type Access = $access;
50
51 const VALID: () = {
52 assert!(Self::VALUE <= 0xfff, "CSR encoding must be 12-bit");
53 $validate
54 };
55 }
56 };
57}
58
59impl_csr_encoding!(Ro, {
60 assert!(
61 (ENCODING >> 10) & 0b11_u16 == 0b11_u16,
62 "Associated access type is read-only but the encoding is not"
63 );
64});
65impl_csr_encoding!(RwSafe, {});
66impl_csr_encoding!(RwUnsafe, {});
67impl_csr_encoding!(WoSafe, {
68 panic!("All CSRs are readable");
69});
70impl_csr_encoding!(WoUnsafe, {
71 panic!("All CSRs are readable");
72});
73
74impl<Encoding, Layout> Csr<Encoding, Layout>
75where
76 Encoding: ControlAndStatusRegisterEncoding,
77 Layout: LayoutOver<u64>,
78{
79 pub const fn new() -> Self {
81 unsafe { Self::from_io(CsrIo::new()) }
83 }
84}
85
86impl<Encoding, Layout> Default for Csr<Encoding, Layout>
87where
88 Encoding: ControlAndStatusRegisterEncoding,
89 Layout: LayoutOver<u64>,
90{
91 fn default() -> Self {
92 Self::new()
93 }
94}
95
96pub struct CsrIo<Encoding: ControlAndStatusRegisterEncoding>(PhantomData<Encoding>);
98
99impl<Encoding: ControlAndStatusRegisterEncoding> CsrIo<Encoding> {
100 pub const fn new() -> Self {
101 const { Encoding::VALID };
104 Self(PhantomData)
105 }
106}
107
108impl<Encoding: ControlAndStatusRegisterEncoding> Default for CsrIo<Encoding> {
109 fn default() -> Self {
110 Self::new()
111 }
112}
113
114impl<Encoding: ControlAndStatusRegisterEncoding> IoHandle for CsrIo<Encoding> {
115 type Base = u64;
116}
117
118#[cfg(target_arch = "riscv64")]
119mod riscv64_only {
120 use core::arch::asm;
121
122 use super::*;
123 use crate::{AtomicIoHandle, ReadHandle, Readable, Writable, WriteHandle};
124
125 impl<Encoding: ControlAndStatusRegisterEncoding> ReadHandle for CsrIo<Encoding>
126 where
127 Encoding::Access: Readable,
128 {
129 #[inline]
130 unsafe fn read_raw(&self) -> u64 {
131 let value: u64;
132 unsafe {
133 asm!(
134 "csrr {value}, {csr}",
135 value = out(reg) value,
136 csr = const Encoding::VALUE,
137 options(nomem, nostack, preserves_flags),
138 )
139 }
140 value
141 }
142 }
143
144 impl<Encoding: ControlAndStatusRegisterEncoding> WriteHandle for CsrIo<Encoding>
145 where
146 Encoding::Access: Writable,
147 {
148 #[inline]
149 unsafe fn write_raw(&self, value: u64) {
150 unsafe {
151 asm!(
152 "csrw {csr}, {value}",
153 value = in(reg) value,
154 csr = const Encoding::VALUE,
155 options(nostack, preserves_flags),
157 )
158 }
159 }
160 }
161
162 impl<Encoding: ControlAndStatusRegisterEncoding> AtomicIoHandle for CsrIo<Encoding>
163 where
164 Encoding::Access: Readable + Writable,
165 {
166 #[inline]
167 unsafe fn atomic_swap_raw(&self, value: u64) -> u64 {
168 let previous: u64;
169 unsafe {
170 asm!(
171 "csrrw {previous}, {csr}, {value}",
172 previous = out(reg) previous,
173 value = in(reg) value,
174 csr = const Encoding::VALUE,
175 options(nostack, preserves_flags),
177 )
178 };
179 previous
180 }
181
182 #[inline]
183 unsafe fn atomic_set_bits_raw(&self, bits: u64) -> u64 {
184 let previous: u64;
185 unsafe {
186 asm!(
187 "csrrs {previous}, {csr}, {bits}",
188 previous = out(reg) previous,
189 bits = in(reg) bits,
190 csr = const Encoding::VALUE,
191 options(nostack, preserves_flags),
193 )
194 };
195 previous
196 }
197
198 #[inline]
199 unsafe fn atomic_clear_bits_raw(&self, bits: u64) -> u64 {
200 let previous: u64;
201 unsafe {
202 asm!(
203 "csrrc {previous}, {csr}, {bits}",
204 previous = out(reg) previous,
205 bits = in(reg) bits,
206 csr = const Encoding::VALUE,
207 options(nostack, preserves_flags),
209 )
210 };
211 previous
212 }
213 }
214}
215
216#[cfg(all(test, target_arch = "riscv64"))]
217mod tests {
218 use super::*;
219
220 #[test]
221 fn csrs() {
222 const TIME: Csr<encoding::time, u64> = Csr::new();
223
224 println!("Current time: {:#x}", TIME.read());
225 }
226}