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

Use typestate for interrupt_occurred/reset_interrupt_flag in the Peripheral traits #181

Open
12 tasks
rrbutani opened this issue Jul 28, 2022 · 0 comments
Open
12 tasks
Assignees
Labels
➕ improvement Chores and fixes: the small things. P-low Low priority T-peripheral traits Topic: Peripheral Traits

Comments

@rrbutani
Copy link
Member

what

We want to make it so that you can only call reset_interrupt_flag after a call to interrupt_occurred for the same pin+peripheral indicated that interrupts are enabled.

This would look something like:

// This is intentionally not a type that users can construct themselves!
//
// It intentionally does *not* impl `Copy` or `Clone`.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PendingGpioInterrupt(GpioPin);
impl PendingGpioInterrupt {
  fn pin(&self) -> GpioPin { self.0 }
}

pub trait Gpio {
  // ...

  fn get_pending_interrupt(&self) -> Option<PendingGpioInterrupt>;
  fn clear_pending_interrupt(&mut self, pending: PendingGpioInterrupt);
}

And then in mem_mapped, Interrupt would change from:

/// Returns true if the interrupt is ready to fire (i.e. pending) regardless
/// of whether the interrupt is enabled.
fn interrupt_ready<'a, I>(interp: &I) -> bool
where
I: InstructionInterpreterPeripheralAccess<'a>,
<I as Deref>::Target: Peripherals<'a>;
/// Returns true if the interrupt is enabled.
fn interrupt_enabled<'a, I>(interp: &I) -> bool
where
I: InstructionInterpreterPeripheralAccess<'a>,
<I as Deref>::Target: Peripherals<'a>;
fn reset_interrupt_flag<'a, I>(interp: &mut I)
where
I: InstructionInterpreterPeripheralAccess<'a>,
<I as Deref>::Target: Peripherals<'a>;

To something like:

pub trait Interrupt {
  type PendingInterrupt;

  // ...

  fn interrupt_pending<I: Ipa>(interp: &I) -> Option<PendingInterrupt>;
  /// just an optimization: we call `interrupt_enabled` first and _then_ `interrupt_ready` so if
  /// `interrupt_ready` for a peripheral is expensive and there's a quick way to check if interrupts are _enabled_, implement this function.
  fn interrupt_enabled<I: Ipa>(interp: &I) -> bool { self.interrupt_ready(interp).is_some() }
  fn clear_pending_interrupt<I: Ipa>(interp: &mut I, pending: Self::PendingInterrupt);
}

steps

  • make the changes described above to the peripheral traits:
    • Gpio
    • Timers
    • Input
    • `Output
  • modify the Interrupt trait in mem_mapped and update the peripheral trait implementations of it for:
    • Gpio
    • Timers
    • Input
    • Output
  • update the logic in interp.rs to support threading through this bit of state to clear_pending_interrupt

where

branch: imp/pending-interrupt-typestate

open questions

@rrbutani rrbutani added ➕ improvement Chores and fixes: the small things. P-low Low priority T-peripheral traits Topic: Peripheral Traits labels Jul 28, 2022
@rrbutani rrbutani self-assigned this Jul 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
➕ improvement Chores and fixes: the small things. P-low Low priority T-peripheral traits Topic: Peripheral Traits
Projects
None yet
Development

No branches or pull requests

1 participant