|  | @@ -9,7 +9,11 @@ extern crate proc_macro2;
 | 
	
		
			
				|  |  |  extern crate syn;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  use proc_macro2::Span;
 | 
	
		
			
				|  |  | -use syn::{parse, spanned::Spanned, FnArg, ItemFn, PathArguments, ReturnType, Type, Visibility};
 | 
	
		
			
				|  |  | +use syn::{
 | 
	
		
			
				|  |  | +    parse::{self, Parse},
 | 
	
		
			
				|  |  | +    spanned::Spanned,
 | 
	
		
			
				|  |  | +    FnArg, ItemFn, LitInt, LitStr, PathArguments, ReturnType, Type, Visibility,
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  use proc_macro::TokenStream;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -205,3 +209,55 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |      .into()
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +struct AsmLoopArgs {
 | 
	
		
			
				|  |  | +    asm_template: String,
 | 
	
		
			
				|  |  | +    count: usize,
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +impl Parse for AsmLoopArgs {
 | 
	
		
			
				|  |  | +    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
 | 
	
		
			
				|  |  | +        let template: LitStr = input.parse().unwrap();
 | 
	
		
			
				|  |  | +        _ = input.parse::<Token![,]>().unwrap();
 | 
	
		
			
				|  |  | +        let count: LitInt = input.parse().unwrap();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        Ok(Self {
 | 
	
		
			
				|  |  | +            asm_template: template.value(),
 | 
	
		
			
				|  |  | +            count: count.base10_parse().unwrap(),
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// Loops an asm expression n times.
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// `loop_asm!` takes 2 arguments, the first is a string literal and the second is a number literal
 | 
	
		
			
				|  |  | +/// See [the formatting syntax documentation in `std::fmt`](../std/fmt/index.html)
 | 
	
		
			
				|  |  | +/// for details.
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// Argument 1 is an assembly expression, all "{}" in this assembly expression will be replaced with the
 | 
	
		
			
				|  |  | +/// current loop index.
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// Argument 2 is the number of loops to do with the provided expression.
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// # Examples
 | 
	
		
			
				|  |  | +///
 | 
	
		
			
				|  |  | +/// ```
 | 
	
		
			
				|  |  | +/// # use riscv_rt_macros::loop_asm;
 | 
	
		
			
				|  |  | +/// unsafe {
 | 
	
		
			
				|  |  | +///     loop_asm!("fmv.w.x f{}, x0", 32); // => core::arch::asm!("fmv.w.x f0, x0") ... core::arch::asm!("fmv.w.x f31, x0")
 | 
	
		
			
				|  |  | +/// }
 | 
	
		
			
				|  |  | +/// ```
 | 
	
		
			
				|  |  | +#[proc_macro]
 | 
	
		
			
				|  |  | +pub fn loop_asm(input: TokenStream) -> TokenStream {
 | 
	
		
			
				|  |  | +    let args = parse_macro_input!(input as AsmLoopArgs);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let tokens = (0..args.count)
 | 
	
		
			
				|  |  | +        .map(|i| {
 | 
	
		
			
				|  |  | +            let i = i.to_string();
 | 
	
		
			
				|  |  | +            let asm = args.asm_template.replace("{}", &i);
 | 
	
		
			
				|  |  | +            format!("core::arch::asm!(\"{}\");", asm)
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +        .collect::<Vec<String>>()
 | 
	
		
			
				|  |  | +        .join("\n");
 | 
	
		
			
				|  |  | +    tokens.parse().unwrap()
 | 
	
		
			
				|  |  | +}
 |