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 assert!(false, "All CSRs are readable");
69});
70impl_csr_encoding!(WoUnsafe, {
71 assert!(false, "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
86pub struct CsrIo<Encoding: ControlAndStatusRegisterEncoding>(PhantomData<Encoding>);
88
89impl<Encoding: ControlAndStatusRegisterEncoding> CsrIo<Encoding> {
90 pub const fn new() -> Self {
91 let _ = Encoding::VALID;
94 Self(PhantomData)
95 }
96}
97
98impl<Encoding: ControlAndStatusRegisterEncoding> IoHandle for CsrIo<Encoding> {
99 type Base = u64;
100}
101
102#[cfg(target_arch = "riscv64")]
103mod riscv64_only {
104 use core::arch::asm;
105
106 use super::*;
107 use crate::{AtomicIoHandle, ReadHandle, Readable, Writable, WriteHandle};
108
109 impl<Encoding: ControlAndStatusRegisterEncoding> ReadHandle for CsrIo<Encoding>
110 where
111 Encoding::Access: Readable,
112 {
113 #[inline]
114 unsafe fn read_raw(&self) -> u64 {
115 let value: u64;
116 unsafe {
117 asm!(
118 "csrr {value}, {csr}",
119 value = out(reg) value,
120 csr = const Encoding::VALUE,
121 options(nomem, nostack, preserves_flags),
122 )
123 }
124 value
125 }
126 }
127
128 impl<Encoding: ControlAndStatusRegisterEncoding> WriteHandle for CsrIo<Encoding>
129 where
130 Encoding::Access: Writable,
131 {
132 #[inline]
133 unsafe fn write_raw(&self, value: u64) {
134 unsafe {
135 asm!(
136 "csrw {csr}, {value}",
137 value = in(reg) value,
138 csr = const Encoding::VALUE,
139 options(nostack, preserves_flags),
141 )
142 }
143 }
144 }
145
146 impl<Encoding: ControlAndStatusRegisterEncoding> AtomicIoHandle for CsrIo<Encoding>
147 where
148 Encoding::Access: Readable + Writable,
149 {
150 #[inline]
151 unsafe fn atomic_swap_raw(&self, value: u64) -> u64 {
152 let previous: u64;
153 unsafe {
154 asm!(
155 "csrrw {previous}, {csr}, {value}",
156 previous = out(reg) previous,
157 value = in(reg) value,
158 csr = const Encoding::VALUE,
159 options(nostack, preserves_flags),
161 )
162 };
163 previous
164 }
165
166 #[inline]
167 unsafe fn atomic_set_bits_raw(&self, bits: u64) -> u64 {
168 let previous: u64;
169 unsafe {
170 asm!(
171 "csrrs {previous}, {csr}, {bits}",
172 previous = out(reg) previous,
173 bits = in(reg) bits,
174 csr = const Encoding::VALUE,
175 options(nostack, preserves_flags),
177 )
178 };
179 previous
180 }
181
182 #[inline]
183 unsafe fn atomic_clear_bits_raw(&self, bits: u64) -> u64 {
184 let previous: u64;
185 unsafe {
186 asm!(
187 "csrrc {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}
199
200#[cfg(all(test, target_arch = "riscv64"))]
201mod tests {
202 use super::*;
203
204 #[test]
205 fn csrs() {
206 const TIME: Csr<encoding::time, u64> = Csr::new();
207
208 println!("Current time: {:#x}", TIME.read());
209 }
210}