Skip to content

Commit de3aaaf

Browse files
authored
Merge pull request #934 from romancardenas/master
`riscv-peripheral` v0.3.0 rework
2 parents 4052ce6 + 7a01f7c commit de3aaaf

File tree

4 files changed

+108
-84
lines changed

4 files changed

+108
-84
lines changed

CHANGELOG.md

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

88
## [Unreleased]
99

10+
- Adapt RISC-V specific codegen for `riscv-peripheral` v0.3.0 rework
11+
- Include `riscv-peripheral` peripherals in `Peripherals` struct
12+
1013
## [v0.36.1] - 2025-04-04
1114

1215
- Update `irx-config`

src/config/riscv.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,16 @@ impl RiscvEnumItem {
5252
#[derive(Clone, PartialEq, Eq, Debug, Default)]
5353
#[non_exhaustive]
5454
pub struct RiscvClintConfig {
55+
pub pub_new: bool,
5556
pub name: String,
56-
pub freq: Option<usize>,
57-
pub async_delay: bool,
57+
pub mtime_freq: usize,
5858
}
5959

6060
#[cfg_attr(feature = "serde", derive(serde::Deserialize), serde(default))]
6161
#[derive(Clone, PartialEq, Eq, Debug, Default)]
6262
#[non_exhaustive]
6363
pub struct RiscvPlicConfig {
64+
pub pub_new: bool,
6465
pub name: String,
6566
pub core_interrupt: Option<String>,
6667
pub hart_id: Option<String>,

src/generate/device.rs

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -219,34 +219,31 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
219219
// Core peripherals are handled above
220220
continue;
221221
}
222-
if config.target == Target::RISCV && riscv::is_riscv_peripheral(p, &config.settings) {
223-
// RISC-V specific peripherals are handled above
224-
continue;
225-
}
226-
227-
debug!("Rendering peripheral {}", p.name);
228-
let periph = peripheral::render(p, &index, config).with_context(|| {
229-
let group_name = p.group_name.as_deref().unwrap_or("No group name");
230-
let mut context_string =
231-
format!("can't render peripheral '{}', group '{group_name}'", p.name);
232-
if let Some(dname) = p.derived_from.as_ref() {
233-
context_string += &format!(", derived from: '{dname}'");
222+
if config.target != Target::RISCV || !riscv::is_riscv_peripheral(p, &config.settings) {
223+
debug!("Rendering peripheral {}", p.name);
224+
let periph = peripheral::render(p, &index, config).with_context(|| {
225+
let group_name = p.group_name.as_deref().unwrap_or("No group name");
226+
let mut context_string =
227+
format!("can't render peripheral '{}', group '{group_name}'", p.name);
228+
if let Some(dname) = p.derived_from.as_ref() {
229+
context_string += &format!(", derived from: '{dname}'");
230+
}
231+
context_string
232+
})?;
233+
234+
out.extend(periph);
235+
236+
if p.registers
237+
.as_ref()
238+
.map(|v| &v[..])
239+
.unwrap_or(&[])
240+
.is_empty()
241+
&& p.derived_from.is_none()
242+
{
243+
// No register block will be generated so don't put this peripheral
244+
// in the `Peripherals` struct
245+
continue;
234246
}
235-
context_string
236-
})?;
237-
238-
out.extend(periph);
239-
240-
if p.registers
241-
.as_ref()
242-
.map(|v| &v[..])
243-
.unwrap_or(&[])
244-
.is_empty()
245-
&& p.derived_from.is_none()
246-
{
247-
// No register block will be generated so don't put this peripheral
248-
// in the `Peripherals` struct
249-
continue;
250247
}
251248
let mut feature_attribute = TokenStream::new();
252249
if config.feature_group && p.group_name.is_some() {

src/generate/riscv.rs

Lines changed: 78 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{svd::Peripheral, util, Config, Settings};
22
use anyhow::Result;
33
use log::debug;
4-
use proc_macro2::TokenStream;
4+
use proc_macro2::{Span, TokenStream};
55
use quote::quote;
66
use std::{collections::HashMap, fmt::Write, str::FromStr};
77

@@ -216,71 +216,93 @@ pub fn render(
216216

217217
let mut riscv_peripherals = TokenStream::new();
218218
if let Some(c) = config.settings.riscv_config.as_ref() {
219-
let harts = match c.harts.is_empty() {
220-
true => vec![],
221-
false => c
222-
.harts
223-
.iter()
224-
.map(|h| (TokenStream::from_str(&h.name).unwrap(), h.value))
225-
.collect::<Vec<_>>(),
219+
let harts = c
220+
.harts
221+
.iter()
222+
.map(|h| (TokenStream::from_str(&h.name).unwrap(), h.value))
223+
.collect::<Vec<_>>();
224+
let harts = match harts.len() {
225+
0 => quote! {},
226+
_ => {
227+
let harts = harts
228+
.iter()
229+
.map(|(name, value)| {
230+
let value = TokenStream::from_str(&format!("{value}")).unwrap();
231+
quote! {crate::interrupt::Hart::#name => #value}
232+
})
233+
.collect::<Vec<_>>();
234+
quote! {
235+
harts [#(#harts),*]
236+
}
237+
}
226238
};
227239
if let Some(clint) = &c.clint {
228240
let p = peripherals.iter().find(|&p| p.name == clint.name).unwrap();
229-
let base = TokenStream::from_str(&format!("base 0x{:X},", p.base_address)).unwrap();
230-
let freq = match clint.freq {
231-
Some(clk) => match clint.async_delay {
232-
true => TokenStream::from_str(&format!("freq {clk}, async_delay,")).unwrap(),
233-
false => TokenStream::from_str(&format!("freq {clk},")).unwrap(),
234-
},
235-
None => quote! {},
236-
};
237-
let mtimecmps = harts
238-
.iter()
239-
.map(|(name, value)| {
240-
let mtimecmp_name = TokenStream::from_str(&format!("mtimecmp{value}")).unwrap();
241-
let doc = format!("[{value}](crate::interrupt::Hart::{name})");
242-
quote! {#mtimecmp_name = (crate::interrupt::Hart::#name, #doc)}
243-
})
244-
.collect::<Vec<_>>();
245-
let mtimecmps = match mtimecmps.len() {
246-
0 => quote! {},
247-
_ => quote! {mtimecmps [ #(#mtimecmps),* ],},
248-
};
249-
let msips = harts
250-
.iter()
251-
.map(|(name, value)| {
252-
let msip_name = TokenStream::from_str(&format!("msip{value}")).unwrap();
253-
let doc = format!("[{value}](crate::interrupt::Hart::{name})");
254-
quote! {#msip_name = (crate::interrupt::Hart::#name, #doc)}
255-
})
256-
.collect::<Vec<_>>();
257-
let msips = match msips.len() {
258-
0 => quote! {},
259-
_ => quote! {msips [ #(#msips),* ],},
241+
242+
let span = Span::call_site();
243+
let vis = match clint.pub_new {
244+
true => quote! {pub},
245+
false => quote! {},
260246
};
247+
let name = util::ident(&p.name, config, "peripheral", span);
248+
let base = TokenStream::from_str(&format!("base 0x{:X},", p.base_address)).unwrap();
249+
let freq = TokenStream::from_str(&format!("mtime_freq {},", clint.mtime_freq)).unwrap();
261250

262251
riscv_peripherals.extend(quote! {
263-
riscv_peripheral::clint_codegen!(#base #freq #mtimecmps #msips);
252+
riscv_peripheral::clint_codegen!(#vis #name, #base #freq #harts);
253+
impl #name {
254+
/// Steal an instance of this peripheral
255+
///
256+
/// # Safety
257+
///
258+
/// Ensure that the new instance of the peripheral cannot be used in a way
259+
/// that may race with any existing instances, for example by only
260+
/// accessing read-only or write-only registers, or by consuming the
261+
/// original peripheral and using critical sections to coordinate
262+
/// access between multiple new instances.
263+
///
264+
/// Additionally, other software such as HALs may rely on only one
265+
/// peripheral instance existing to ensure memory safety; ensure
266+
/// no stolen instances are passed to such software.
267+
#[inline]
268+
pub unsafe fn steal() -> Self {
269+
Self::new()
270+
}
271+
}
264272
});
265273
}
266274
if let Some(plic) = &c.plic {
267275
let p = peripherals.iter().find(|&p| p.name == plic.name).unwrap();
268-
let base = TokenStream::from_str(&format!("base 0x{:X},", p.base_address)).unwrap();
269-
let ctxs = harts
270-
.iter()
271-
.map(|(name, value)| {
272-
let ctx_name = TokenStream::from_str(&format!("ctx{value}")).unwrap();
273-
let doc = format!("[{value}](crate::interrupt::Hart::{name})");
274-
quote! {#ctx_name = (crate::interrupt::Hart::#name, #doc)}
275-
})
276-
.collect::<Vec<_>>();
277-
let ctxs = match ctxs.len() {
278-
0 => quote! {},
279-
_ => quote! {ctxs [ #(#ctxs),* ],},
276+
277+
let span = Span::call_site();
278+
let vis = match plic.pub_new {
279+
true => quote! {pub},
280+
false => quote! {},
280281
};
282+
let name = util::ident(&p.name, config, "peripheral", span);
283+
let base = TokenStream::from_str(&format!("base 0x{:X},", p.base_address)).unwrap();
281284

282285
riscv_peripherals.extend(quote! {
283-
riscv_peripheral::plic_codegen!(#base #ctxs);
286+
riscv_peripheral::plic_codegen!(#vis #name, #base #harts);
287+
impl #name {
288+
/// Steal an instance of this peripheral
289+
///
290+
/// # Safety
291+
///
292+
/// Ensure that the new instance of the peripheral cannot be used in a way
293+
/// that may race with any existing instances, for example by only
294+
/// accessing read-only or write-only registers, or by consuming the
295+
/// original peripheral and using critical sections to coordinate
296+
/// access between multiple new instances.
297+
///
298+
/// Additionally, other software such as HALs may rely on only one
299+
/// peripheral instance existing to ensure memory safety; ensure
300+
/// no stolen instances are passed to such software.
301+
#[inline]
302+
pub unsafe fn steal() -> Self {
303+
Self::new()
304+
}
305+
}
284306
});
285307

286308
if let Some(core_interrupt) = &plic.core_interrupt {
@@ -294,8 +316,9 @@ pub fn render(
294316
mod_items.extend(quote! {
295317
#[cfg(feature = "rt")]
296318
#[riscv_rt::core_interrupt(CoreInterrupt::#core_interrupt)]
297-
fn plic_handler() {
298-
let claim = crate::PLIC::#ctx.claim();
319+
unsafe fn plic_handler() {
320+
let plic = unsafe { crate::#name::steal() };
321+
let claim = plic.#ctx.claim();
299322
if let Some(s) = claim.claim::<ExternalInterrupt>() {
300323
unsafe { _dispatch_external_interrupt(s.number()) }
301324
claim.complete(s);

0 commit comments

Comments
 (0)