1
1
//! Devices for the Core Local Interruptor (CLINT) and Advanced CLINT (ACLINT) peripherals.
2
2
//!
3
3
//! CLINT pecification: <https://github.com/pulp-platform/clint>
4
- //! ACLINT Specification: <https://chromitem-soc.readthedocs.io/en/latest/clint.html >
4
+ //! ACLINT Specification: <https://github.com/riscvarchive/riscv-aclint/blob/main/riscv-aclint.adoc >
5
5
6
6
pub mod mswi;
7
7
pub mod mtimer;
@@ -15,48 +15,78 @@ pub use riscv_pac::HartIdNumber; // re-export useful riscv-pac traits
15
15
///
16
16
/// * This trait must only be implemented on a PAC of a target with a CLINT peripheral.
17
17
/// * The CLINT peripheral base address `BASE` must be valid for the target device.
18
+ /// * The CLINT peripheral clock frequency `MTIME_FREQ` must be valid for the target device.
18
19
pub unsafe trait Clint : Copy {
19
20
/// Base address of the CLINT peripheral.
20
21
const BASE : usize ;
22
+ /// Clock frequency of the CLINT's [`MTIME`](mtimer::MTIME) register.
23
+ const MTIME_FREQ : usize ;
21
24
}
22
25
23
26
/// Interface for a CLINT peripheral.
24
27
///
25
28
/// The RISC-V standard does not specify a fixed location for the CLINT.
26
29
/// Thus, each platform must specify the base address of the CLINT on the platform.
27
- /// The base address, as well as all the associated types, are defined in the [`Clint`] trait.
30
+ /// The base address and clock frequency are defined in the [`Clint`] trait.
28
31
///
29
32
/// The CLINT standard allows up to 4_095 different HARTs connected to the CLINT.
30
33
/// Each HART has an assigned index starting from 0 to up to 4_094.
31
34
/// In this way, each HART's timer and software interrupts can be independently configured.
32
35
#[ allow( clippy:: upper_case_acronyms) ]
33
36
#[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
34
- pub struct CLINT < C : Clint > {
37
+ pub struct CLINT < C > {
35
38
_marker : core:: marker:: PhantomData < C > ,
36
39
}
37
40
38
41
impl < C : Clint > CLINT < C > {
39
- const MTIMECMP_OFFSET : usize = 0x4000 ;
42
+ #[ inline]
43
+ /// Creates a new `CLINT` peripheral.
44
+ pub const fn new ( ) -> Self {
45
+ Self {
46
+ _marker : core:: marker:: PhantomData ,
47
+ }
48
+ }
40
49
41
- const MTIME_OFFSET : usize = 0xBFF8 ;
50
+ /// Returns the [`MSWI`](mswi::MSWI) device.
51
+ #[ inline]
52
+ pub const fn mswi ( & self ) -> mswi:: MSWI < C > {
53
+ mswi:: MSWI :: new ( )
54
+ }
42
55
43
- /// Returns the `MSWI` peripheral .
56
+ /// Returns the [`MTIMER`](mtimer::MTIMER) device .
44
57
#[ inline]
45
- pub const fn mswi ( ) -> mswi:: MSWI {
46
- // SAFETY: valid base address
47
- unsafe { mswi:: MSWI :: new ( C :: BASE ) }
58
+ pub const fn mtimer ( & self ) -> mtimer:: MTIMER < C > {
59
+ mtimer:: MTIMER :: new ( )
48
60
}
49
61
50
- /// Returns the `MTIMER` peripheral .
62
+ /// Returns `true` if a machine timer **OR** software interrupt is pending .
51
63
#[ inline]
52
- pub const fn mtimer ( ) -> mtimer:: MTIMER {
53
- // SAFETY: valid base address
54
- unsafe {
55
- mtimer:: MTIMER :: new (
56
- C :: BASE + Self :: MTIMECMP_OFFSET ,
57
- C :: BASE + Self :: MTIME_OFFSET ,
58
- )
59
- }
64
+ pub fn is_interrupting ( & self ) -> bool {
65
+ self . mswi ( ) . is_interrupting ( ) || self . mtimer ( ) . is_interrupting ( )
66
+ }
67
+
68
+ /// Returns `true` if machine timer **OR** software interrupts are enabled.
69
+ #[ inline]
70
+ pub fn is_enabled ( & self ) -> bool {
71
+ self . mswi ( ) . is_enabled ( ) || self . mtimer ( ) . is_enabled ( )
72
+ }
73
+
74
+ /// Enables machine timer **AND** software interrupts to allow the CLINT to trigger interrupts.
75
+ ///
76
+ /// # Safety
77
+ ///
78
+ /// Enabling the `CLINT` may break mask-based critical sections.
79
+ #[ inline]
80
+ pub unsafe fn enable ( & self ) {
81
+ self . mswi ( ) . enable ( ) ;
82
+ self . mtimer ( ) . enable ( ) ;
83
+ }
84
+
85
+ /// Disables machine timer **AND** software interrupts to prevent the CLINT from triggering interrupts.
86
+ #[ inline]
87
+ pub fn disable ( & self ) {
88
+ self . mswi ( ) . disable ( ) ;
89
+ self . mtimer ( ) . disable ( ) ;
60
90
}
61
91
}
62
92
@@ -111,16 +141,22 @@ pub(crate) mod test {
111
141
// Call CLINT macro with a base address and a list of mtimecmps for easing access to per-HART mtimecmp regs.
112
142
crate :: clint_codegen!(
113
143
base 0x0200_0000 ,
114
- mtimecmps [ mtimecmp0= ( HartId :: H0 , "`H0`" ) , mtimecmp1= ( HartId :: H1 , "`H1`" ) , mtimecmp2= ( HartId :: H2 , "`H2`" ) ] ,
115
- msips [ msip0= ( HartId :: H0 , "`H0`" ) , msip1= ( HartId :: H1 , "`H1`" ) , msip2= ( HartId :: H2 , "`H2`" ) ] ,
144
+ mtime_freq 32_768 ,
145
+ harts [ HartId :: H0 => 0 , HartId :: H1 => 1 , HartId :: H2 => 2 ] ,
116
146
) ;
117
147
118
- let mswi = CLINT :: mswi ( ) ;
119
- let mtimer = CLINT :: mtimer ( ) ;
148
+ let clint = CLINT :: new ( ) ;
149
+
150
+ let mswi = clint. mswi ( ) ;
151
+ let mtimer = clint. mtimer ( ) ;
120
152
121
- assert_eq ! ( mswi. msip0. get_ptr( ) as usize , 0x0200_0000 ) ;
122
- assert_eq ! ( mtimer. mtimecmp0. get_ptr( ) as usize , 0x0200_4000 ) ;
123
- assert_eq ! ( mtimer. mtime. get_ptr( ) as usize , 0x0200_bff8 ) ;
153
+ let msip0 = mswi. msip ( HartId :: H0 ) ;
154
+ let msip1 = mswi. msip ( HartId :: H1 ) ;
155
+ let msip2 = mswi. msip ( HartId :: H2 ) ;
156
+
157
+ assert_eq ! ( msip0. get_ptr( ) as usize , 0x0200_0000 ) ;
158
+ assert_eq ! ( msip1. get_ptr( ) as usize , 0x0200_0000 + 4 ) ; // 4 bytes per register
159
+ assert_eq ! ( msip2. get_ptr( ) as usize , 0x0200_0000 + 2 * 4 ) ;
124
160
125
161
let mtimecmp0 = mtimer. mtimecmp ( HartId :: H0 ) ;
126
162
let mtimecmp1 = mtimer. mtimecmp ( HartId :: H1 ) ;
@@ -130,13 +166,15 @@ pub(crate) mod test {
130
166
assert_eq ! ( mtimecmp1. get_ptr( ) as usize , 0x0200_4000 + 8 ) ; // 8 bytes per register
131
167
assert_eq ! ( mtimecmp2. get_ptr( ) as usize , 0x0200_4000 + 2 * 8 ) ;
132
168
133
- assert_eq ! ( CLINT :: mtime( ) , mtimer. mtime) ;
134
- assert_eq ! ( CLINT :: mtimecmp0( ) , mtimer. mtimecmp( HartId :: H0 ) ) ;
135
- assert_eq ! ( CLINT :: mtimecmp1( ) , mtimer. mtimecmp( HartId :: H1 ) ) ;
136
- assert_eq ! ( CLINT :: mtimecmp2( ) , mtimer. mtimecmp( HartId :: H2 ) ) ;
169
+ let mtime = mtimer. mtime ( ) ;
170
+ assert_eq ! ( mtime. get_ptr( ) as usize , 0x0200_bff8 ) ;
171
+
172
+ assert_eq ! ( clint. mtimecmp0( ) , mtimer. mtimecmp( HartId :: H0 ) ) ;
173
+ assert_eq ! ( clint. mtimecmp1( ) , mtimer. mtimecmp( HartId :: H1 ) ) ;
174
+ assert_eq ! ( clint. mtimecmp2( ) , mtimer. mtimecmp( HartId :: H2 ) ) ;
137
175
138
- assert_eq ! ( CLINT :: msip0( ) , mswi. msip( HartId :: H0 ) ) ;
139
- assert_eq ! ( CLINT :: msip1( ) , mswi. msip( HartId :: H1 ) ) ;
140
- assert_eq ! ( CLINT :: msip2( ) , mswi. msip( HartId :: H2 ) ) ;
176
+ assert_eq ! ( clint . msip0( ) , mswi. msip( HartId :: H0 ) ) ;
177
+ assert_eq ! ( clint . msip1( ) , mswi. msip( HartId :: H1 ) ) ;
178
+ assert_eq ! ( clint . msip2( ) , mswi. msip( HartId :: H2 ) ) ;
141
179
}
142
180
}
0 commit comments