1
1
use crate :: { svd:: Peripheral , util, Config , Settings } ;
2
2
use anyhow:: Result ;
3
3
use log:: debug;
4
- use proc_macro2:: TokenStream ;
4
+ use proc_macro2:: { Span , TokenStream } ;
5
5
use quote:: quote;
6
6
use std:: { collections:: HashMap , fmt:: Write , str:: FromStr } ;
7
7
@@ -216,71 +216,93 @@ pub fn render(
216
216
217
217
let mut riscv_peripherals = TokenStream :: new ( ) ;
218
218
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
+ }
226
238
} ;
227
239
if let Some ( clint) = & c. clint {
228
240
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 ! { } ,
260
246
} ;
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 ( ) ;
261
250
262
251
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
+ }
264
272
} ) ;
265
273
}
266
274
if let Some ( plic) = & c. plic {
267
275
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 ! { } ,
280
281
} ;
282
+ let name = util:: ident ( & p. name , config, "peripheral" , span) ;
283
+ let base = TokenStream :: from_str ( & format ! ( "base 0x{:X}," , p. base_address) ) . unwrap ( ) ;
281
284
282
285
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
+ }
284
306
} ) ;
285
307
286
308
if let Some ( core_interrupt) = & plic. core_interrupt {
@@ -294,8 +316,9 @@ pub fn render(
294
316
mod_items. extend ( quote ! {
295
317
#[ cfg( feature = "rt" ) ]
296
318
#[ 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( ) ;
299
322
if let Some ( s) = claim. claim:: <ExternalInterrupt >( ) {
300
323
unsafe { _dispatch_external_interrupt( s. number( ) ) }
301
324
claim. complete( s) ;
0 commit comments