1pub mod spec;
6
7use crate::{Accessible, IoHandle, LayoutOver, Register};
8
9use core::marker::PhantomData;
10
11pub trait SystemRegisterSpec {
14 const OP0: u8;
16
17 const OP1: u8;
19
20 const CRN: u8;
22
23 const CRM: u8;
25
26 const OP2: u8;
28
29 type Access: Accessible;
31
32 const VALID: () = {
34 assert!(Self::OP0 == 2 || Self::OP0 == 3, "op0 must be 2 or 3");
35 assert!(Self::OP1 <= 7, "op1 must be in between 0 and 7");
36 assert!(Self::CRN <= 15, "CRn must be in between 0 and 15");
37 assert!(Self::CRM <= 15, "CRm must be in between 0 and 15");
38 assert!(Self::OP2 <= 7, "op2 must be in between 0 and 7");
39 };
40}
41
42pub struct SysRegSpec<
45 const OP0: u8,
46 const OP1: u8,
47 const CRN: u8,
48 const CRM: u8,
49 const OP2: u8,
50 Access: Accessible,
51>(PhantomData<Access>);
52
53impl<const OP0: u8, const OP1: u8, const CRN: u8, const CRM: u8, const OP2: u8, Access: Accessible>
54 SystemRegisterSpec for SysRegSpec<OP0, OP1, CRN, CRM, OP2, Access>
55{
56 const OP0: u8 = OP0;
57 const OP1: u8 = OP1;
58 const CRN: u8 = CRN;
59 const CRM: u8 = CRM;
60 const OP2: u8 = OP2;
61 type Access = Access;
62}
63
64pub type SysReg<Spec, Layout> =
79 Register<Layout, <Spec as SystemRegisterSpec>::Access, SysRegIo<Spec>>;
80
81impl<Spec, Layout> SysReg<Spec, Layout>
82where
83 Spec: SystemRegisterSpec,
84 Layout: LayoutOver<u64>,
85{
86 pub const fn new() -> Self {
88 unsafe { Self::from_io(SysRegIo::new()) }
90 }
91}
92
93pub struct SysRegIo<Spec: SystemRegisterSpec>(PhantomData<Spec>);
95
96impl<Spec: SystemRegisterSpec> SysRegIo<Spec> {
97 pub const fn new() -> Self {
98 let _ = Spec::VALID;
101 Self(PhantomData)
102 }
103}
104
105impl<Spec: SystemRegisterSpec> IoHandle for SysRegIo<Spec> {
106 type Base = u64;
107}
108
109#[cfg(target_arch = "aarch64")]
110mod arm64_only {
111 use core::arch::asm;
112
113 use super::*;
114 use crate::{ReadHandle, Readable, Writable, WriteHandle};
115
116 impl<Spec: SystemRegisterSpec> ReadHandle for SysRegIo<Spec>
117 where
118 Spec::Access: Readable,
119 {
120 #[inline]
121 unsafe fn read_raw(&self) -> u64 {
122 let value: u64;
123 unsafe {
124 asm!(
125 "mrs {value}, S{op0}_{op1}_C{crn}_C{crm}_{op2}",
126 value = out(reg) value,
127 op0 = const Spec::OP0,
128 op1 = const Spec::OP1,
129 crn = const Spec::CRN,
130 crm = const Spec::CRM,
131 op2 = const Spec::OP2,
132 options(nomem, nostack, preserves_flags),
133 )
134 }
135 value
136 }
137 }
138
139 impl<Spec: SystemRegisterSpec> WriteHandle for SysRegIo<Spec>
140 where
141 Spec::Access: Writable,
142 {
143 #[inline]
144 unsafe fn write_raw(&self, value: u64) {
145 unsafe {
146 asm!(
147 "msr S{op0}_{op1}_C{crn}_C{crm}_{op2}, {value}",
148 value = in(reg) value,
149 op0 = const Spec::OP0,
150 op1 = const Spec::OP1,
151 crn = const Spec::CRN,
152 crm = const Spec::CRM,
153 op2 = const Spec::OP2,
154 options(nostack, preserves_flags),
156 )
157 }
158 }
159 }
160}
161
162#[cfg(all(test, target_arch = "aarch64"))]
163mod tests {
164 use super::*;
165
166 #[test]
167 fn sysregs() {
168 const TPIDR_EL0: SysReg<spec::TPIDR_EL0, u64> = SysReg::new();
169
170 println!("TPIDR_EL0: {:#x}", TPIDR_EL0.read());
171 }
172}