Skip to content

Commit a7fbb58

Browse files
committed
CLINT rework
1 parent d7fd706 commit a7fbb58

File tree

12 files changed

+358
-744
lines changed

12 files changed

+358
-744
lines changed

riscv-peripheral/CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- Rework of CLINT peripheral to use methods instead of associated functions.
13+
This change follows the `svd2rust` pattern, making the ecosystem more consistent.
14+
- Simplify `clint!` macro using the `Deref` trait.
15+
16+
### Removed
17+
18+
- Removed support for `embedded-hal-async`, as it was not flexible enough to be
19+
used in different targets (single HART, multi HART...). Instead, each chip must
20+
have its own `chip-hal-async` crate that properly adapts to its specific needs.
21+
1022
### Fixed
1123

1224
- `clippy` fixes

riscv-peripheral/Cargo.toml

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "riscv-peripheral"
3-
version = "0.2.1"
3+
version = "0.3.0-rc.1"
44
edition = "2021"
55
rust-version = "1.75"
66
repository = "https://github.com/rust-embedded/riscv"
@@ -15,16 +15,10 @@ license = "ISC"
1515

1616
[dependencies]
1717
embedded-hal = "1.0.0"
18-
embedded-hal-async = { version = "1.0.0", optional = true }
18+
paste = "1.0"
1919
riscv = { path = "../riscv", version = "0.13.0" }
2020
riscv-pac = { path = "../riscv-pac", version = "0.2.0" }
2121

22-
[dev-dependencies]
23-
heapless = "0.8.0"
24-
25-
[features]
26-
aclint-hal-async = ["embedded-hal-async"]
27-
2822
[package.metadata.docs.rs]
2923
all-features = true
3024
default-target = "riscv64imac-unknown-none-elf"

riscv-peripheral/examples/e310x.rs

Lines changed: 2 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -139,68 +139,15 @@ unsafe impl PriorityNumber for Priority {
139139
}
140140
}
141141

142-
#[cfg(feature = "aclint-hal-async")]
143142
riscv_peripheral::clint_codegen!(
144143
base 0x0200_0000,
145-
freq 32_768,
146-
async_delay,
147-
mtimecmps [mtimecmp0=(HartId::H0,"`H0`")],
148-
msips [msip0=(HartId::H0,"`H0`")],
149-
);
150-
151-
#[cfg(not(feature = "aclint-hal-async"))]
152-
riscv_peripheral::clint_codegen!(
153-
base 0x0200_0000,
154-
freq 32_768,
155-
mtimecmps [mtimecmp0=(HartId::H0,"`H0`")],
156-
msips [msip0=(HartId::H0,"`H0`")],
144+
mtime_freq 32_768,
145+
harts [HartId::H0 => 0],
157146
);
158147

159148
riscv_peripheral::plic_codegen!(
160149
base 0x0C00_0000,
161150
ctxs [ctx0=(HartId::H0,"`H0`")],
162151
);
163152

164-
#[cfg(feature = "aclint-hal-async")]
165-
/// extern functions needed by the `riscv-peripheral` crate for the `async` feature.
166-
///
167-
/// # Note
168-
///
169-
/// The functionality in this module is just to illustrate how to enable the `async` feature
170-
/// The timer queue used here, while functional, is unsound and should not be used in production.
171-
/// In this case, you should protect the timer queue with a mutex or critical section.
172-
/// For a more robust implementation, use proper timer queues such as the ones provided by `embassy-time`
173-
mod async_no_mangle {
174-
use super::CLINT;
175-
use heapless::binary_heap::{BinaryHeap, Min};
176-
use riscv_peripheral::{aclint::mtimer::MTIMER, hal_async::aclint::Timer};
177-
178-
const N_TIMERS: usize = 16;
179-
static mut TIMER_QUEUE: BinaryHeap<Timer, Min, N_TIMERS> = BinaryHeap::new();
180-
181-
#[no_mangle]
182-
fn _riscv_peripheral_aclint_mtimer() -> MTIMER {
183-
CLINT::mtimer()
184-
}
185-
186-
#[no_mangle]
187-
fn _riscv_peripheral_aclint_push_timer(t: Timer) -> Result<(), Timer> {
188-
unsafe { TIMER_QUEUE.push(t) }
189-
}
190-
191-
#[no_mangle]
192-
fn _riscv_peripheral_aclint_wake_timers(current_tick: u64) -> Option<u64> {
193-
let mut next_expires = None;
194-
while let Some(t) = unsafe { TIMER_QUEUE.peek() } {
195-
if t.expires() > current_tick {
196-
next_expires = Some(t.expires());
197-
break;
198-
}
199-
let t = unsafe { TIMER_QUEUE.pop() }.unwrap();
200-
t.waker().wake_by_ref();
201-
}
202-
next_expires
203-
}
204-
}
205-
206153
fn main() {}

riscv-peripheral/src/aclint.rs

Lines changed: 70 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
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
66
pub mod mswi;
77
pub 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.
1819
pub 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

3841
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+
}
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

Comments
 (0)