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
93impl<Spec, Layout> Default for SysReg<Spec, Layout>
94where
95 Spec: SystemRegisterSpec,
96 Layout: LayoutOver<u64>,
97{
98 fn default() -> Self {
99 Self::new()
100 }
101}
102
103pub struct SysRegIo<Spec: SystemRegisterSpec>(PhantomData<Spec>);
105
106impl<Spec: SystemRegisterSpec> SysRegIo<Spec> {
107 pub const fn new() -> Self {
108 const { Spec::VALID };
111 Self(PhantomData)
112 }
113}
114
115impl<Spec: SystemRegisterSpec> Default for SysRegIo<Spec> {
116 fn default() -> Self {
117 Self::new()
118 }
119}
120
121impl<Spec: SystemRegisterSpec> IoHandle for SysRegIo<Spec> {
122 type Base = u64;
123}
124
125#[cfg(target_arch = "aarch64")]
126mod arm64_only {
127 use core::arch::asm;
128
129 use super::*;
130 use crate::{ReadHandle, Readable, Writable, WriteHandle};
131
132 impl<Spec: SystemRegisterSpec> ReadHandle for SysRegIo<Spec>
133 where
134 Spec::Access: Readable,
135 {
136 #[inline]
137 unsafe fn read_raw(&self) -> u64 {
138 let value: u64;
139 unsafe {
140 asm!(
141 "mrs {value}, S{op0}_{op1}_C{crn}_C{crm}_{op2}",
142 value = out(reg) value,
143 op0 = const Spec::OP0,
144 op1 = const Spec::OP1,
145 crn = const Spec::CRN,
146 crm = const Spec::CRM,
147 op2 = const Spec::OP2,
148 options(nomem, nostack, preserves_flags),
149 )
150 }
151 value
152 }
153 }
154
155 impl<Spec: SystemRegisterSpec> WriteHandle for SysRegIo<Spec>
156 where
157 Spec::Access: Writable,
158 {
159 #[inline]
160 unsafe fn write_raw(&self, value: u64) {
161 unsafe {
162 asm!(
163 "msr S{op0}_{op1}_C{crn}_C{crm}_{op2}, {value}",
164 value = in(reg) value,
165 op0 = const Spec::OP0,
166 op1 = const Spec::OP1,
167 crn = const Spec::CRN,
168 crm = const Spec::CRM,
169 op2 = const Spec::OP2,
170 options(nostack, preserves_flags),
172 )
173 }
174 }
175 }
176}
177
178#[cfg(all(test, target_arch = "aarch64"))]
179mod tests {
180 use super::*;
181
182 #[test]
183 fn sysregs() {
184 const TPIDR_EL0: SysReg<spec::TPIDR_EL0, u64> = SysReg::new();
185
186 println!("TPIDR_EL0: {:#x}", TPIDR_EL0.read());
187 }
188}