Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interrupt generation for riscv #46

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 57 additions & 11 deletions src/generate/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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![];
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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<Self> {
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" {
Expand Down Expand Up @@ -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)
}
15 changes: 15 additions & 0 deletions src/generate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,21 @@ 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.
#[derive(Debug)]
pub struct Options {
common_module: CommonModule,
defmt_feature: Option<String>,
target: Target,
}

impl Default for Options {
Expand All @@ -90,6 +98,7 @@ impl Options {
Self {
common_module: CommonModule::Builtin,
defmt_feature: Some("defmt".into()),
target: Target::default(),
}
}

Expand Down Expand Up @@ -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<TokenStream> {
Expand Down
13 changes: 12 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<generate::Target>,
}

/// Reformat a YAML
Expand Down Expand Up @@ -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())?;

Expand Down