diff --git a/src/generate/device.rs b/src/generate/device.rs index dd546fb..453af31 100644 --- a/src/generate/device.rs +++ b/src/generate/device.rs @@ -4,6 +4,7 @@ use anyhow::Result; use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; +use crate::generate::Target; use crate::ir::*; use crate::util::{self, StringExt}; @@ -22,6 +23,7 @@ pub fn render(opts: &super::Options, ir: &IR, d: &Device, path: &str) -> Result< let span = Span::call_site(); let mut interrupts = TokenStream::new(); + let mut interrupt_match = TokenStream::new(); let mut peripherals = TokenStream::new(); let mut vectors = TokenStream::new(); let mut names = vec![]; @@ -52,10 +54,14 @@ pub fn render(opts: &super::Options, ir: &IR, d: &Device, path: &str) -> Result< #[doc = #description] #name_uc = #value, }); + interrupt_match.extend(quote!(#value => Ok(Interrupt::#name_uc),)); + vectors.extend(quote!(Vector { _handler: #name_uc },)); names.push(name_uc); } + let max_interrupt_number = util::unsuffixed((pos - 1) as u64); + for p in sorted(&d.peripherals, |p| p.base_address) { let name = Ident::new(&p.name, span); let address = util::hex_usize(p.base_address); @@ -90,14 +96,43 @@ pub fn render(opts: &super::Options, ir: &IR, d: &Device, path: &str) -> Result< pub enum Interrupt { #interrupts } + )); - unsafe impl cortex_m::interrupt::InterruptNumber for Interrupt { - #[inline(always)] - fn number(self) -> u16 { - self as u16 - } + match opts.target { + Target::Riscv => { + out.extend(quote!( + unsafe impl riscv::InterruptNumber for Interrupt { + /// Returns the number of the interrupt + #[inline(always)] + fn number(self) -> usize { + self as usize + } + + fn from_number(number: usize) -> riscv::result::Result { + match number { + #interrupt_match + _ => Err(riscv::result::Error::InvalidVariant(number)), + } + } + + const MAX_INTERRUPT_NUMBER: usize = #max_interrupt_number; + } + )); } + Target::CortexM => { + out.extend(quote!( + unsafe impl cortex_m::interrupt::InterruptNumber for Interrupt { + /// Returns the number of the interrupt + #[inline(always)] + fn number(self) -> u16 { + self as u16 + } + } + )); + } + } + out.extend(quote!( #[cfg(feature = "rt")] mod _vectors { extern "C" { @@ -128,12 +163,23 @@ pub fn render(opts: &super::Options, ir: &IR, d: &Device, path: &str) -> Result< }); } - out.extend(quote! { - #[cfg(feature = "rt")] - pub use cortex_m_rt::interrupt; - #[cfg(feature = "rt")] - pub use Interrupt as interrupt; - }); + match opts.target { + Target::CortexM => { + out.extend(quote! { + #[cfg(feature = "rt")] + pub use cortex_m_rt::interrupt; + #[cfg(feature = "rt")] + pub use Interrupt as interrupt; + }); + } + Target::Riscv => { + // TODO: Do we need to export something from riscv_rt here? + out.extend(quote! { + #[cfg(feature = "rt")] + pub use Interrupt as interrupt; + }); + } + } Ok(out) } diff --git a/src/generate/mod.rs b/src/generate/mod.rs index 15214e7..98f294b 100644 --- a/src/generate/mod.rs +++ b/src/generate/mod.rs @@ -66,6 +66,13 @@ pub enum CommonModule { External(TokenStream), } +#[derive(clap::ValueEnum, Debug, Default, Clone, Copy, PartialEq)] +pub enum Target { + #[default] + CortexM, + Riscv, +} + /// Options for the code generator. /// /// See the individual methods for the different options you can change. @@ -73,6 +80,7 @@ pub enum CommonModule { pub struct Options { common_module: CommonModule, defmt_feature: Option, + target: Target, } impl Default for Options { @@ -90,6 +98,7 @@ impl Options { Self { common_module: CommonModule::Builtin, defmt_feature: Some("defmt".into()), + target: Target::default(), } } @@ -129,6 +138,12 @@ impl Options { pub fn defmt_feature(&self) -> Option<&str> { self.defmt_feature.as_deref() } + + /// Select what kind fo target to generate code for. + pub fn with_target(mut self, target: Target) -> Self { + self.target = target; + self + } } pub fn render(ir: &IR, opts: &Options) -> Result { diff --git a/src/main.rs b/src/main.rs index f01c66f..babf8de 100755 --- a/src/main.rs +++ b/src/main.rs @@ -93,6 +93,9 @@ struct Generate { /// Do not add defmt support to the generated code at all. #[clap(long)] no_defmt: bool, + + #[clap(long)] + target: Option, } /// Reformat a YAML @@ -281,9 +284,17 @@ fn gen(args: Generate) -> Result<()> { true => None, false => Some(args.defmt_feature), }; + + let target = match args.target { + None => generate::Target::CortexM, + Some(target) => target, + }; + let generate_opts = generate::Options::default() .with_common_module(common_module) - .with_defmt_feature(defmt_feature); + .with_defmt_feature(defmt_feature) + .with_target(target); + let items = generate::render(&ir, &generate_opts).unwrap(); fs::write("lib.rs", items.to_string())?;