riscv_csr/
csr.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! `ReadWriteRiscvCsr` type for RISC-V CSRs.
6
7use core::marker::PhantomData;
8
9use tock_registers::fields::Field;
10use tock_registers::interfaces::{Readable, Writeable};
11use tock_registers::{RegisterLongName, UIntLike};
12
13pub const MINSTRETH: usize = 0xB82;
14pub const MINSTRET: usize = 0xB02;
15pub const MCYCLEH: usize = 0xB80;
16pub const MCYCLE: usize = 0xB00;
17pub const MIE: usize = 0x304;
18pub const MTVEC: usize = 0x305;
19pub const MSTATUS: usize = 0x300;
20pub const UTVEC: usize = 0x005;
21pub const STVEC: usize = 0x105;
22pub const MSCRATCH: usize = 0x340;
23pub const MEPC: usize = 0x341;
24pub const MCAUSE: usize = 0x342;
25pub const MTVAL: usize = 0x343;
26pub const MIP: usize = 0x344;
27pub const MSECCFG: usize = 0x747;
28pub const MSECCFGH: usize = 0x757;
29pub const PMPCFG0: usize = 0x3A0;
30pub const PMPCFG1: usize = 0x3A1;
31pub const PMPCFG2: usize = 0x3A2;
32pub const PMPCFG3: usize = 0x3A3;
33pub const PMPCFG4: usize = 0x3A4;
34pub const PMPCFG5: usize = 0x3A5;
35pub const PMPCFG6: usize = 0x3A6;
36pub const PMPCFG7: usize = 0x3A7;
37pub const PMPCFG8: usize = 0x3A8;
38pub const PMPCFG9: usize = 0x3A9;
39pub const PMPCFG10: usize = 0x3AA;
40pub const PMPCFG11: usize = 0x3AB;
41pub const PMPCFG12: usize = 0x3AC;
42pub const PMPCFG13: usize = 0x3AD;
43pub const PMPCFG14: usize = 0x3AE;
44pub const PMPCFG15: usize = 0x3AF;
45pub const PMPADDR0: usize = 0x3B0;
46pub const PMPADDR1: usize = 0x3B1;
47pub const PMPADDR2: usize = 0x3B2;
48pub const PMPADDR3: usize = 0x3B3;
49pub const PMPADDR4: usize = 0x3B4;
50pub const PMPADDR5: usize = 0x3B5;
51pub const PMPADDR6: usize = 0x3B6;
52pub const PMPADDR7: usize = 0x3B7;
53pub const PMPADDR8: usize = 0x3B8;
54pub const PMPADDR9: usize = 0x3B9;
55pub const PMPADDR10: usize = 0x3BA;
56pub const PMPADDR11: usize = 0x3BB;
57pub const PMPADDR12: usize = 0x3BC;
58pub const PMPADDR13: usize = 0x3BD;
59pub const PMPADDR14: usize = 0x3BE;
60pub const PMPADDR15: usize = 0x3BF;
61pub const PMPADDR16: usize = 0x3C0;
62pub const PMPADDR17: usize = 0x3C1;
63pub const PMPADDR18: usize = 0x3C2;
64pub const PMPADDR19: usize = 0x3C3;
65pub const PMPADDR20: usize = 0x3C4;
66pub const PMPADDR21: usize = 0x3C5;
67pub const PMPADDR22: usize = 0x3C6;
68pub const PMPADDR23: usize = 0x3C7;
69pub const PMPADDR24: usize = 0x3C8;
70pub const PMPADDR25: usize = 0x3C9;
71pub const PMPADDR26: usize = 0x3CA;
72pub const PMPADDR27: usize = 0x3CB;
73pub const PMPADDR28: usize = 0x3CC;
74pub const PMPADDR29: usize = 0x3CD;
75pub const PMPADDR30: usize = 0x3CE;
76pub const PMPADDR31: usize = 0x3CF;
77pub const PMPADDR32: usize = 0x3D0;
78pub const PMPADDR33: usize = 0x3D1;
79pub const PMPADDR34: usize = 0x3D2;
80pub const PMPADDR35: usize = 0x3D3;
81pub const PMPADDR36: usize = 0x3D4;
82pub const PMPADDR37: usize = 0x3D5;
83pub const PMPADDR38: usize = 0x3D6;
84pub const PMPADDR39: usize = 0x3D7;
85pub const PMPADDR40: usize = 0x3D8;
86pub const PMPADDR41: usize = 0x3D9;
87pub const PMPADDR42: usize = 0x3DA;
88pub const PMPADDR43: usize = 0x3DB;
89pub const PMPADDR44: usize = 0x3DC;
90pub const PMPADDR45: usize = 0x3DD;
91pub const PMPADDR46: usize = 0x3DE;
92pub const PMPADDR47: usize = 0x3DF;
93pub const PMPADDR48: usize = 0x3E0;
94pub const PMPADDR49: usize = 0x3E1;
95pub const PMPADDR50: usize = 0x3E2;
96pub const PMPADDR51: usize = 0x3E3;
97pub const PMPADDR52: usize = 0x3E4;
98pub const PMPADDR53: usize = 0x3E5;
99pub const PMPADDR54: usize = 0x3E6;
100pub const PMPADDR55: usize = 0x3E7;
101pub const PMPADDR56: usize = 0x3E8;
102pub const PMPADDR57: usize = 0x3E9;
103pub const PMPADDR58: usize = 0x3EA;
104pub const PMPADDR59: usize = 0x3EB;
105pub const PMPADDR60: usize = 0x3EC;
106pub const PMPADDR61: usize = 0x3ED;
107pub const PMPADDR62: usize = 0x3EE;
108pub const PMPADDR63: usize = 0x3EF;
109
110/// Read/Write registers.
111#[derive(Copy, Clone)]
112pub struct ReadWriteRiscvCsr<T: UIntLike, R: RegisterLongName, const V: usize> {
113    associated_register: PhantomData<R>,
114    associated_length: PhantomData<T>,
115}
116
117// morally speaking, these should be implemented; however not yet needed
118//pub struct WriteOnlyRiscvCsr<T: UIntLike, R: RegisterLongName = ()> {
119//value: T,
120//associated_register: PhantomData<R>}
121
122//pub struct ReadOnlyRiscvCsr<T: UIntLike, R: RegisterLongName = ()> {
123//value: T,
124//associated_register: PhantomData<R>}
125
126impl<R: RegisterLongName, const V: usize> ReadWriteRiscvCsr<usize, R, V> {
127    pub const fn new() -> Self {
128        ReadWriteRiscvCsr {
129            associated_register: PhantomData,
130            associated_length: PhantomData,
131        }
132    }
133
134    // Special methods only available on RISC-V CSRs, not found in the
135    // usual tock-registers interface, others implemented through the
136    // respective [`Readable`] and [`Writeable`] trait implementations
137
138    /// Atomically swap the contents of a CSR
139    ///
140    /// Reads the current value of a CSR and replaces it with the
141    /// specified value in a single instruction, returning the
142    /// previous value.
143    ///
144    /// This method corresponds to the RISC-V `CSRRW rd, csr, rs1`
145    /// instruction where `rs1 = in(reg) value_to_set` and `rd =
146    /// out(reg) <return value>`.
147    #[cfg(any(
148        doc,
149        all(
150            any(target_arch = "riscv32", target_arch = "riscv64"),
151            target_os = "none"
152        )
153    ))]
154    #[inline]
155    pub fn atomic_replace(&self, val_to_set: usize) -> usize {
156        use core::arch::asm;
157        let r: usize;
158        unsafe {
159            asm!(
160                "
161    csrrw {rd}, {csr}, {rs1}
162                ",
163                rd = out(reg) r,
164                csr = const V,
165                rs1 = in(reg) val_to_set,
166            );
167        }
168        r
169    }
170
171    /// Atomically swap the contents of a CSR
172    ///
173    /// Reads the current value of a CSR and replaces it with the
174    /// specified value in a single instruction, returning the
175    /// previous value.
176    ///
177    /// This method corresponds to the RISC-V `CSRRW rd, csr, rs1`
178    /// instruction where `rs1 = in(reg) value_to_set` and `rd =
179    /// out(reg) <return value>`.
180    // Mock implementations for tests on Travis-CI.
181    #[cfg(not(any(
182        doc,
183        all(
184            any(target_arch = "riscv32", target_arch = "riscv64"),
185            target_os = "none"
186        )
187    )))]
188    pub fn atomic_replace(&self, _value_to_set: usize) -> usize {
189        unimplemented!("RISC-V CSR {} Atomic Read/Write", V)
190    }
191
192    /// Atomically read a CSR and set bits specified in a bitmask
193    ///
194    /// This method corresponds to the RISC-V `CSRRS rd, csr, rs1`
195    /// instruction where `rs1 = in(reg) bitmask` and `rd = out(reg)
196    /// <return value>`.
197    #[cfg(any(
198        doc,
199        all(
200            any(target_arch = "riscv32", target_arch = "riscv64"),
201            target_os = "none"
202        )
203    ))]
204    #[inline]
205    pub fn read_and_set_bits(&self, bitmask: usize) -> usize {
206        use core::arch::asm;
207        let r: usize;
208        unsafe {
209            asm!(
210                "
211    csrrs {rd}, {csr}, {rs1}
212                ",
213                rd = out(reg) r,
214                csr = const V,
215                rs1 = in(reg) bitmask
216            );
217        }
218        r
219    }
220
221    /// Atomically read a CSR and set bits specified in a bitmask
222    ///
223    /// This method corresponds to the RISC-V `CSRRS rd, csr, rs1`
224    /// instruction where `rs1 = in(reg) bitmask` and `rd = out(reg)
225    /// <return value>`.
226    // Mock implementations for tests on Travis-CI.
227    #[cfg(not(any(
228        doc,
229        all(
230            any(target_arch = "riscv32", target_arch = "riscv64"),
231            target_os = "none"
232        )
233    )))]
234    pub fn read_and_set_bits(&self, bitmask: usize) -> usize {
235        unimplemented!(
236            "RISC-V CSR {} Atomic Read and Set Bits, bitmask {:04x}",
237            V,
238            bitmask
239        )
240    }
241
242    /// Atomically read a CSR and clear bits specified in a bitmask
243    ///
244    /// This method corresponds to the RISC-V `CSRRC rd, csr, rs1`
245    /// instruction where `rs1 = in(reg) bitmask` and `rd = out(reg)
246    /// <return value>`.
247    #[cfg(any(
248        doc,
249        all(
250            any(target_arch = "riscv32", target_arch = "riscv64"),
251            target_os = "none"
252        )
253    ))]
254    #[inline]
255    pub fn read_and_clear_bits(&self, bitmask: usize) -> usize {
256        use core::arch::asm;
257        let r: usize;
258        unsafe {
259            asm!(
260                "
261    csrrc {rd}, {csr}, {rs1}
262                ",
263                rd = out(reg) r,
264                csr = const V,
265                rs1 = in(reg) bitmask,
266            );
267        }
268        r
269    }
270
271    /// Atomically read a CSR and clear bits specified in a bitmask
272    ///
273    /// This method corresponds to the RISC-V `CSRRC rd, csr, rs1`
274    /// instruction where `rs1 = in(reg) bitmask` and `rd = out(reg)
275    /// <return value>`.
276    // Mock implementations for tests on Travis-CI.
277    #[cfg(not(any(
278        doc,
279        all(
280            any(target_arch = "riscv32", target_arch = "riscv64"),
281            target_os = "none"
282        )
283    )))]
284    pub fn read_and_clear_bits(&self, bitmask: usize) -> usize {
285        unimplemented!(
286            "RISC-V CSR {} Atomic Read and Clear Bits, bitmask {:04x}",
287            V,
288            bitmask
289        )
290    }
291
292    /// Atomically read field and set all bits to 1
293    ///
294    /// This method corresponds to the RISC-V `CSRRS rd, csr, rs1`
295    /// instruction, where `rs1` is the bitmask described by the
296    /// [`Field`].
297    ///
298    /// The previous value of the field is returned.
299    #[inline]
300    pub fn read_and_set_field(&self, field: Field<usize, R>) -> usize {
301        field.read(self.read_and_set_bits(field.mask << field.shift))
302    }
303
304    /// Atomically read field and set all bits to 0
305    ///
306    /// This method corresponds to the RISC-V `CSRRC rd, csr, rs1`
307    /// instruction, where `rs1` is the bitmask described by the
308    /// [`Field`].
309    ///
310    /// The previous value of the field is returned.
311    #[inline]
312    pub fn read_and_clear_field(&self, field: Field<usize, R>) -> usize {
313        field.read(self.read_and_clear_bits(field.mask << field.shift))
314    }
315}
316
317impl<R: RegisterLongName, const V: usize> Readable for ReadWriteRiscvCsr<usize, R, V> {
318    type T = usize;
319    type R = R;
320
321    #[cfg(any(
322        doc,
323        all(
324            any(target_arch = "riscv32", target_arch = "riscv64"),
325            target_os = "none"
326        )
327    ))]
328    #[inline]
329    fn get(&self) -> usize {
330        use core::arch::asm;
331        let r: usize;
332        unsafe {
333            asm!("csrr {rd}, {csr}", rd = out(reg) r, csr = const V);
334        }
335        r
336    }
337
338    // Mock implementations for tests on Travis-CI.
339    #[cfg(not(any(
340        doc,
341        all(
342            any(target_arch = "riscv32", target_arch = "riscv64"),
343            target_os = "none"
344        )
345    )))]
346    fn get(&self) -> usize {
347        unimplemented!("reading RISC-V CSR {}", V)
348    }
349}
350
351impl<R: RegisterLongName, const V: usize> Writeable for ReadWriteRiscvCsr<usize, R, V> {
352    type T = usize;
353    type R = R;
354
355    #[cfg(any(
356        doc,
357        all(
358            any(target_arch = "riscv32", target_arch = "riscv64"),
359            target_os = "none"
360        )
361    ))]
362    #[inline]
363    fn set(&self, val_to_set: usize) {
364        use core::arch::asm;
365        unsafe {
366            asm!("csrw {csr}, {rs}", rs = in(reg) val_to_set, csr = const V);
367        }
368    }
369
370    #[cfg(not(any(
371        doc,
372        all(
373            any(target_arch = "riscv32", target_arch = "riscv64"),
374            target_os = "none"
375        )
376    )))]
377    fn set(&self, _val_to_set: usize) {
378        unimplemented!("writing RISC-V CSR {}", V)
379    }
380}