c64 0.1.0-alpha.1

Driver for the Commodore 64 platform
Documentation
//! Interrupts.

pub use bare_metal::{CriticalSection, Mutex};

extern "C" {
    fn disable_interrupts();
    fn enable_interrupts();
}

/// Disables interrupts.
#[inline]
pub fn disable() {
    unsafe { disable_interrupts() };

    // Ensure no subsequent memory accesses are reordered to before interrupts are
    // disabled.
    // TODO: Do this once rust-mos supports it.
    // compiler_fence(Ordering::SeqCst);
}

/// Enables interrupts.
///
/// # Safety
///
/// - Do not call this function inside an [`interrupt::free`] critical section.
///
/// [`interrupt::free`]: free
#[inline]
pub unsafe fn enable() {
    // Ensure no preceeding memory accesses are reordered to after interrupts are enabled.
    // TODO: Do this once rust-mos supports it.
    // compiler_fence(Ordering::SeqCst);

    unsafe { enable_interrupts() };
}

/// Execute closure `f` in an interrupt-free context.
///
/// This as also known as a "critical section".
#[inline]
pub fn free<F, R>(f: F) -> R
where
    F: FnOnce(&CriticalSection) -> R,
{
    // Backup previous state of P register.
    let p = super::register::p::read();

    // Disable interrupts.
    disable();

    let r = f(&unsafe { CriticalSection::new() });

    // Re-enable interrupts if we disabled them.
    if (p & 0b00000100) == 0 {
        unsafe { enable() };
    }

    r
}