11use crate :: { svd:: Peripheral , util, Config , Settings } ;
22use anyhow:: Result ;
33use log:: debug;
4- use proc_macro2:: TokenStream ;
4+ use proc_macro2:: { Span , TokenStream } ;
55use quote:: quote;
66use 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