From 01e041c2dd086a572994aeacc24142debb5551d3 Mon Sep 17 00:00:00 2001 From: Dominik Boehi Date: Fri, 10 Oct 2025 18:00:14 +0200 Subject: [PATCH] Interrupt generation for riscv --- src/generate/device.rs | 68 +++++++++++++++++++++++++++++++++++------- src/generate/mod.rs | 15 ++++++++++ src/main.rs | 15 +++++++++- 3 files changed, 86 insertions(+), 12 deletions(-) diff --git a/src/generate/device.rs b/src/generate/device.rs index d5eb623..f42b7f0 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); @@ -86,14 +92,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 { unsafe extern "C" { @@ -124,12 +159,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 f652803..2f3a2f4 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: DefmtOption, + target: Target, } /// Option for generating code for `defmt` support. @@ -101,6 +109,7 @@ impl Options { Self { common_module: CommonModule::Builtin, defmt: DefmtOption::Feature("defmt".to_owned()), + target: Target::default(), } } @@ -136,6 +145,12 @@ impl Options { pub fn defmt(&self) -> &DefmtOption { &self.defmt } + + /// 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 0448052..33a4cd7 100755 --- a/src/main.rs +++ b/src/main.rs @@ -148,6 +148,10 @@ struct GenShared { /// Add defmt support to the generated code unconditionally. #[clap(long)] yes_defmt: bool, + + /// Specify the target architecture for the generated code. + #[clap(long)] + target: Option, } fn main() -> Result<()> { @@ -283,6 +287,7 @@ fn gen(args: Generate) -> Result<()> { } let generate_opts = get_generate_opts(args.gen_shared)?; + let items = generate::render(&ir, &generate_opts).unwrap(); fs::write("lib.rs", items.to_string())?; @@ -488,8 +493,16 @@ fn get_generate_opts(args: GenShared) -> Result { (true, true) => bail!("--no-defmt and --yes-defmt are mutually exclusive"), }; + let target = match args.target { + None => generate::Target::CortexM, + Some(target) => target, + }; + + let opts = generate::Options::default() .with_common_module(common_module) - .with_defmt(defmt); + .with_defmt(defmt) + .with_target(target); + Ok(opts) }