c64 0.1.0-alpha.1

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

use core::marker::PhantomData;
use core::ops;

pub mod asp;
#[cfg(feature = "ultimate")]
pub mod uci;

/// Commodore 64 peripherals.
#[allow(non_snake_case)]
#[non_exhaustive]
pub struct Peripherals {
    /// The address space.
    pub ASP: ASP,

    /// The FAC register.
    pub FAC: FAC,

    /// The ARG register.
    pub ARG: ARG,

    /// The work area for floating point to string conversions.
    pub FPSTR: FPSTR,

    /// The Ultimate Command Interface.
    #[cfg(feature = "ultimate")]
    pub UCI: UCI,
}

// NOTE `no_mangle` is used here to prevent linking different minor versions of this crate
// as that would let you `take` the peripherals more than once (one per minor version).
#[no_mangle]
static PERIPHERALS: () = ();

/// Set to `true` when `take` or `steal` was called to make `Peripherals` a singleton.
static mut TAKEN: bool = false;

impl Peripherals {
    /// Returns all the Commodore 64 peripherals *once*.
    #[inline]
    pub fn take() -> Option<Self> {
        super::interrupt::free(|_| {
            if unsafe { TAKEN } {
                None
            } else {
                Some(unsafe { Peripherals::steal() })
            }
        })
    }

    /// Unchecked version of [`Peripherals::take`].
    #[inline]
    pub unsafe fn steal() -> Self {
        unsafe {
            TAKEN = true;

            Peripherals {
                ASP: ASP {
                    _marker: PhantomData,
                },
                FAC: FAC {
                    _marker: PhantomData,
                },
                ARG: ARG {
                    _marker: PhantomData,
                },
                FPSTR: FPSTR {
                    _marker: PhantomData,
                },
                #[cfg(feature = "ultimate")]
                UCI: UCI {
                    _marker: PhantomData,
                },
            }
        }
    }
}

/// The address space.
pub struct ASP {
    _marker: PhantomData<*const ()>,
}

unsafe impl Send for ASP {}

impl ASP {
    /// Pointer to the register block.
    pub const PTR: *const self::asp::RegisterBlock = 0x0000 as *const _;
}

impl ops::Deref for ASP {
    type Target = self::asp::RegisterBlock;

    #[inline(always)]
    fn deref(&self) -> &Self::Target {
        unsafe { &*Self::PTR }
    }
}

/// The FAC register.
pub struct FAC {
    _marker: PhantomData<*const ()>,
}

unsafe impl Send for FAC {}

/// The ARG register.
pub struct ARG {
    _marker: PhantomData<*const ()>,
}

unsafe impl Send for ARG {}

/// The work area for floating point to string conversions.
pub struct FPSTR {
    _marker: PhantomData<*const ()>,
}

unsafe impl Send for FPSTR {}

/// The Ultimate Command Interface.
#[cfg(feature = "ultimate")]
pub struct UCI {
    _marker: PhantomData<*const ()>,
}

#[cfg(feature = "ultimate")]
unsafe impl Send for UCI {}

#[cfg(feature = "ultimate")]
impl UCI {
    /// Pointer to the register block.
    pub const PTR: *const self::uci::RegisterBlock = 0xdf1b as *const _;
}

#[cfg(feature = "ultimate")]
impl ops::Deref for UCI {
    type Target = self::uci::RegisterBlock;

    #[inline(always)]
    fn deref(&self) -> &Self::Target {
        unsafe { &*Self::PTR }
    }
}