Skip to content

Commit 09dc978

Browse files
Merge pull request #288 from rust-embedded/riscv-peripheral-rework
`riscv-peripheral` rework
2 parents 74c2091 + 4aba650 commit 09dc978

File tree

20 files changed

+567
-1124
lines changed

20 files changed

+567
-1124
lines changed

.github/workflows/riscv-peripheral.yaml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,8 @@ jobs:
3131
with:
3232
toolchain: ${{ matrix.toolchain }}
3333
targets: ${{ matrix.target }}
34-
- name: Build (no features)
34+
- name: Build
3535
run: cargo build --package riscv-peripheral --target ${{ matrix.target }}
36-
- name: Build (all features)
37-
run: cargo build --package riscv-peripheral --target ${{ matrix.target }} --all-features
3836

3937
# On MacOS, Ubuntu, and Windows, we run the tests.
4038
build-others:
@@ -48,10 +46,8 @@ jobs:
4846
steps:
4947
- uses: actions/checkout@v3
5048
- uses: dtolnay/rust-toolchain@stable
51-
- name: Build (no features)
49+
- name: Test
5250
run: cargo test --package riscv-peripheral
53-
- name: Build (all features)
54-
run: cargo test --package riscv-peripheral --all-features
5551

5652
# Job to check that all the builds succeeded
5753
build-check:

riscv-peripheral/CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,23 @@ 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_codegen!` macro using the `Deref` trait.
15+
- Rework of PLIC peripherals to use methods instead of associated functions.
16+
This change follows the `svd2rust` pattern, making the ecosystem more consistent.
17+
- Simplify `plic_codegen!` macro using the `Deref` trait.
18+
- Macros allow now to customize the struct name for CLINT and PLIC.
19+
- Macros allow now to customize the visibility of the `new` function for CLINT and PLIC.
20+
21+
### Removed
22+
23+
- Removed support for `embedded-hal-async`, as it was not flexible enough to be
24+
used in different targets (single HART, multi HART...). Instead, each chip must
25+
have its own `chip-hal-async` crate that properly adapts to its specific needs.
26+
1027
### Fixed
1128

1229
- `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: 20 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,16 @@
11
//! Peripheral definitions for the E310x chip.
2+
//!
23
//! This is a simple example of how to use the `riscv-peripheral` crate to generate
34
//! peripheral definitions for a target.
45
5-
use riscv_pac::{
6-
result::{Error, Result},
7-
ExternalInterruptNumber, HartIdNumber, InterruptNumber, PriorityNumber,
8-
};
9-
106
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7+
#[riscv::pac_enum(unsafe HartIdNumber)]
118
pub enum HartId {
129
H0 = 0,
1310
}
1411

15-
unsafe impl HartIdNumber for HartId {
16-
const MAX_HART_ID_NUMBER: usize = Self::H0 as usize;
17-
18-
#[inline]
19-
fn number(self) -> usize {
20-
self as _
21-
}
22-
23-
#[inline]
24-
fn from_number(number: usize) -> Result<Self> {
25-
match number {
26-
0 => Ok(Self::H0),
27-
_ => Err(Error::InvalidVariant(number)),
28-
}
29-
}
30-
}
31-
3212
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
33-
#[repr(usize)]
13+
#[riscv::pac_enum(unsafe ExternalInterruptNumber)]
3414
pub enum Interrupt {
3515
WATCHDOG = 1,
3616
RTC = 2,
@@ -86,29 +66,8 @@ pub enum Interrupt {
8666
I2C0 = 52,
8767
}
8868

89-
unsafe impl InterruptNumber for Interrupt {
90-
const MAX_INTERRUPT_NUMBER: usize = Self::I2C0 as usize;
91-
92-
#[inline]
93-
fn number(self) -> usize {
94-
self as _
95-
}
96-
97-
#[inline]
98-
fn from_number(number: usize) -> Result<Self> {
99-
if number == 0 || number > Self::MAX_INTERRUPT_NUMBER {
100-
Err(Error::InvalidVariant(number))
101-
} else {
102-
// SAFETY: valid interrupt number
103-
Ok(unsafe { core::mem::transmute::<usize, Interrupt>(number) })
104-
}
105-
}
106-
}
107-
108-
unsafe impl ExternalInterruptNumber for Interrupt {}
109-
11069
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
111-
#[repr(usize)]
70+
#[riscv::pac_enum(unsafe PriorityNumber)]
11271
pub enum Priority {
11372
P0 = 0,
11473
P1 = 1,
@@ -120,87 +79,30 @@ pub enum Priority {
12079
P7 = 7,
12180
}
12281

123-
unsafe impl PriorityNumber for Priority {
124-
const MAX_PRIORITY_NUMBER: usize = Self::P7 as usize;
125-
126-
#[inline]
127-
fn number(self) -> usize {
128-
self as _
129-
}
130-
131-
#[inline]
132-
fn from_number(number: usize) -> Result<Self> {
133-
if number > Self::MAX_PRIORITY_NUMBER {
134-
Err(Error::InvalidVariant(number))
135-
} else {
136-
// SAFETY: valid priority number
137-
Ok(unsafe { core::mem::transmute::<usize, Priority>(number) })
138-
}
139-
}
140-
}
141-
142-
#[cfg(feature = "aclint-hal-async")]
143-
riscv_peripheral::clint_codegen!(
144-
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"))]
82+
// We can define CLINT::new() as a public, safe function
15283
riscv_peripheral::clint_codegen!(
84+
pub CLINT,
15385
base 0x0200_0000,
154-
freq 32_768,
155-
mtimecmps [mtimecmp0=(HartId::H0,"`H0`")],
156-
msips [msip0=(HartId::H0,"`H0`")],
86+
mtime_freq 32_768,
87+
harts [HartId::H0 => 0]
15788
);
15889

90+
// We can define PLIC::new() as a private, safe function...
15991
riscv_peripheral::plic_codegen!(
92+
PLIC,
16093
base 0x0C00_0000,
161-
ctxs [ctx0=(HartId::H0,"`H0`")],
94+
harts [HartId::H0 => 0]
16295
);
16396

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
97+
// ... and then implement a public, unsafe function to steal the PLIC instance
98+
// Usually, this function is implemented by svd2rust, but we do it manually here
99+
impl PLIC {
100+
pub unsafe fn steal() -> Self {
101+
PLIC::new()
203102
}
204103
}
205104

206-
fn main() {}
105+
fn main() {
106+
let _clint = CLINT::new();
107+
let _plic = unsafe { PLIC::steal() };
108+
}

0 commit comments

Comments
 (0)