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!("csrrw {rd}, {csr}, {rs1}",
160                 rd = out(reg) r,
161                 csr = const V,
162                 rs1 = in(reg) val_to_set);
163        }
164        r
165    }
166
167    /// Atomically swap the contents of a CSR
168    ///
169    /// Reads the current value of a CSR and replaces it with the
170    /// specified value in a single instruction, returning the
171    /// previous value.
172    ///
173    /// This method corresponds to the RISC-V `CSRRW rd, csr, rs1`
174    /// instruction where `rs1 = in(reg) value_to_set` and `rd =
175    /// out(reg) <return value>`.
176    // Mock implementations for tests on Travis-CI.
177    #[cfg(not(any(
178        doc,
179        all(
180            any(target_arch = "riscv32", target_arch = "riscv64"),
181            target_os = "none"
182        )
183    )))]
184    pub fn atomic_replace(&self, _value_to_set: usize) -> usize {
185        unimplemented!("RISC-V CSR {} Atomic Read/Write", V)
186    }
187
188    /// Atomically read a CSR and set bits specified in a bitmask
189    ///
190    /// This method corresponds to the RISC-V `CSRRS rd, csr, rs1`
191    /// instruction where `rs1 = in(reg) bitmask` and `rd = out(reg)
192    /// <return value>`.
193    #[cfg(any(
194        doc,
195        all(
196            any(target_arch = "riscv32", target_arch = "riscv64"),
197            target_os = "none"
198        )
199    ))]
200    #[inline]
201    pub fn read_and_set_bits(&self, bitmask: usize) -> usize {
202        use core::arch::asm;
203        let r: usize;
204        unsafe {
205            asm!("csrrs {rd}, {csr}, {rs1}",
206                 rd = out(reg) r,
207                 csr = const V,
208                 rs1 = in(reg) bitmask);
209        }
210        r
211    }
212
213    /// Atomically read a CSR and set bits specified in a bitmask
214    ///
215    /// This method corresponds to the RISC-V `CSRRS rd, csr, rs1`
216    /// instruction where `rs1 = in(reg) bitmask` and `rd = out(reg)
217    /// <return value>`.
218    // Mock implementations for tests on Travis-CI.
219    #[cfg(not(any(
220        doc,
221        all(
222            any(target_arch = "riscv32", target_arch = "riscv64"),
223            target_os = "none"
224        )
225    )))]
226    pub fn read_and_set_bits(&self, bitmask: usize) -> usize {
227        unimplemented!(
228            "RISC-V CSR {} Atomic Read and Set Bits, bitmask {:04x}",
229            V,
230            bitmask
231        )
232    }
233
234    /// Atomically read a CSR and clear bits specified in a bitmask
235    ///
236    /// This method corresponds to the RISC-V `CSRRC rd, csr, rs1`
237    /// instruction where `rs1 = in(reg) bitmask` and `rd = out(reg)
238    /// <return value>`.
239    #[cfg(any(
240        doc,
241        all(
242            any(target_arch = "riscv32", target_arch = "riscv64"),
243            target_os = "none"
244        )
245    ))]
246    #[inline]
247    pub fn read_and_clear_bits(&self, bitmask: usize) -> usize {
248        use core::arch::asm;
249        let r: usize;
250        unsafe {
251            asm!("csrrc {rd}, {csr}, {rs1}",
252                 rd = out(reg) r,
253                 csr = const V,
254                 rs1 = in(reg) bitmask);
255        }
256        r
257    }
258
259    /// Atomically read a CSR and clear bits specified in a bitmask
260    ///
261    /// This method corresponds to the RISC-V `CSRRC rd, csr, rs1`
262    /// instruction where `rs1 = in(reg) bitmask` and `rd = out(reg)
263    /// <return value>`.
264    // Mock implementations for tests on Travis-CI.
265    #[cfg(not(any(
266        doc,
267        all(
268            any(target_arch = "riscv32", target_arch = "riscv64"),
269            target_os = "none"
270        )
271    )))]
272    pub fn read_and_clear_bits(&self, bitmask: usize) -> usize {
273        unimplemented!(
274            "RISC-V CSR {} Atomic Read and Clear Bits, bitmask {:04x}",
275            V,
276            bitmask
277        )
278    }
279
280    /// Atomically read field and set all bits to 1
281    ///
282    /// This method corresponds to the RISC-V `CSRRS rd, csr, rs1`
283    /// instruction, where `rs1` is the bitmask described by the
284    /// [`Field`].
285    ///
286    /// The previous value of the field is returned.
287    #[inline]
288    pub fn read_and_set_field(&self, field: Field<usize, R>) -> usize {
289        field.read(self.read_and_set_bits(field.mask << field.shift))
290    }
291
292    /// Atomically read field and set all bits to 0
293    ///
294    /// This method corresponds to the RISC-V `CSRRC 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_clear_field(&self, field: Field<usize, R>) -> usize {
301        field.read(self.read_and_clear_bits(field.mask << field.shift))
302    }
303}
304
305impl<R: RegisterLongName, const V: usize> Readable for ReadWriteRiscvCsr<usize, R, V> {
306    type T = usize;
307    type R = R;
308
309    #[cfg(any(
310        doc,
311        all(
312            any(target_arch = "riscv32", target_arch = "riscv64"),
313            target_os = "none"
314        )
315    ))]
316    #[inline]
317    fn get(&self) -> usize {
318        use core::arch::asm;
319        let r: usize;
320        unsafe {
321            asm!("csrr {rd}, {csr}", rd = out(reg) r, csr = const V);
322        }
323        r
324    }
325
326    // Mock implementations for tests on Travis-CI.
327    #[cfg(not(any(
328        doc,
329        all(
330            any(target_arch = "riscv32", target_arch = "riscv64"),
331            target_os = "none"
332        )
333    )))]
334    fn get(&self) -> usize {
335        unimplemented!("reading RISC-V CSR {}", V)
336    }
337}
338
339impl<R: RegisterLongName, const V: usize> Writeable for ReadWriteRiscvCsr<usize, R, V> {
340    type T = usize;
341    type R = R;
342
343    #[cfg(any(
344        doc,
345        all(
346            any(target_arch = "riscv32", target_arch = "riscv64"),
347            target_os = "none"
348        )
349    ))]
350    #[inline]
351    fn set(&self, val_to_set: usize) {
352        use core::arch::asm;
353        unsafe {
354            asm!("csrw {csr}, {rs}", rs = in(reg) val_to_set, csr = const V);
355        }
356    }
357
358    #[cfg(not(any(
359        doc,
360        all(
361            any(target_arch = "riscv32", target_arch = "riscv64"),
362            target_os = "none"
363        )
364    )))]
365    fn set(&self, _val_to_set: usize) {
366        unimplemented!("writing RISC-V CSR {}", V)
367    }
368}