11//! Devices for the Core Local Interruptor (CLINT) and Advanced CLINT (ACLINT) peripherals.
22//!
33//! 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 >
55
66pub mod mswi;
77pub mod mtimer;
@@ -15,48 +15,78 @@ pub use riscv_pac::HartIdNumber; // re-export useful riscv-pac traits
1515///
1616/// * This trait must only be implemented on a PAC of a target with a CLINT peripheral.
1717/// * 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.
1819pub unsafe trait Clint : Copy {
1920 /// Base address of the CLINT peripheral.
2021 const BASE : usize ;
22+ /// Clock frequency of the CLINT's [`MTIME`](mtimer::MTIME) register.
23+ const MTIME_FREQ : usize ;
2124}
2225
2326/// Interface for a CLINT peripheral.
2427///
2528/// The RISC-V standard does not specify a fixed location for the CLINT.
2629/// 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.
2831///
2932/// The CLINT standard allows up to 4_095 different HARTs connected to the CLINT.
3033/// Each HART has an assigned index starting from 0 to up to 4_094.
3134/// In this way, each HART's timer and software interrupts can be independently configured.
3235#[ allow( clippy:: upper_case_acronyms) ]
3336#[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
34- pub struct CLINT < C : Clint > {
37+ pub struct CLINT < C > {
3538 _marker : core:: marker:: PhantomData < C > ,
3639}
3740
3841impl < 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+ }
4049
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+ }
4255
43- /// Returns the `MSWI` peripheral .
56+ /// Returns the [`MTIMER`](mtimer::MTIMER) device .
4457 #[ 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 ( )
4860 }
4961
50- /// Returns the `MTIMER` peripheral .
62+ /// Returns `true` if a machine timer **OR** software interrupt is pending .
5163 #[ 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 ( ) ;
6090 }
6191}
6292
@@ -111,16 +141,22 @@ pub(crate) mod test {
111141 // Call CLINT macro with a base address and a list of mtimecmps for easing access to per-HART mtimecmp regs.
112142 crate :: clint_codegen!(
113143 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 ] ,
116146 ) ;
117147
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 ( ) ;
120152
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 ) ;
124160
125161 let mtimecmp0 = mtimer. mtimecmp ( HartId :: H0 ) ;
126162 let mtimecmp1 = mtimer. mtimecmp ( HartId :: H1 ) ;
@@ -130,13 +166,15 @@ pub(crate) mod test {
130166 assert_eq ! ( mtimecmp1. get_ptr( ) as usize , 0x0200_4000 + 8 ) ; // 8 bytes per register
131167 assert_eq ! ( mtimecmp2. get_ptr( ) as usize , 0x0200_4000 + 2 * 8 ) ;
132168
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 ) ) ;
137175
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 ) ) ;
141179 }
142180}
0 commit comments