#![no_std]
#![feature(asm_experimental_arch)]
#![feature(asm_const)]
use crate::ai::AudioInterface;
use crate::cp0::Cp0;
use crate::cp1::Cp1;
use crate::mi::MipsInterface;
use crate::pi::PeripheralInterface;
use crate::si::SerialInterface;
use crate::vi::VideoInterface;
macro_rules! regfn_ro {
($block:ident, $reg:ident, $reg_name:expr, $datatype:ident) => {
#[doc = concat!("Creates a temporary pointer to the [`", stringify!($block), "`], and reads data from its ", stringify!($reg_name), " register.")]
#[inline(always)]
pub fn $reg() -> $datatype {
unsafe { $block::new().$reg.read() }
}
};
}
macro_rules! regfn_wo {
($block:ident, $reg:ident, $reg_name:expr, $datatype:ident) => {
paste::paste! {
#[doc = concat!("Creates a temporary pointer to the [`", stringify!($block), "`], and writes data to its ", stringify!($reg_name), " register.")]
#[inline(always)]
pub unsafe fn [<set_ $reg>](data: $datatype) {
$block::new().$reg.write(data);
}
}
}
}
macro_rules! regfn_rw {
($block:ident, $reg:ident, $reg_name:expr, $datatype:ident) => {
regfn_ro!($block, $reg, $reg_name, $datatype);
regfn_wo!($block, $reg, $reg_name, $datatype);
paste::paste! {
#[doc = concat!("Creates a temporary pointer to the [`", stringify!($block), "`], reads data from its ", stringify!($reg_name), " register, modifies the data, then finally writes back into the register.")]
#[inline(always)]
pub unsafe fn [<modify_ $reg>]<F: FnOnce($datatype) -> $datatype>(func: F) {
$block::new().$reg.modify(func);
}
}
}
}
macro_rules! regfn_ro_union {
($block:ident, $reg:ident, $reg_name:expr, $uniontype:ident) => {
paste::paste! {
#[doc = concat!("Creates a temporary pointer to the [`", stringify!($block), "`], and reads data from its ", stringify!($reg_name), " register.")]
#[inline(always)]
pub fn $reg() -> [<$uniontype Read>] {
unsafe { $block::new().$reg.read().read }
}
}
};
}
macro_rules! regfn_wo_union {
($block:ident, $reg:ident, $reg_name:expr, $uniontype:ident) => {
paste::paste! {
#[doc = concat!("Creates a temporary pointer to the [`", stringify!($block), "`], and writes data to its ", stringify!($reg_name), " register.")]
#[inline(always)]
pub unsafe fn [<set_ $reg>](data: [<$uniontype Write>]) {
$block::new().$reg.write($uniontype { write: data });
}
}
}
}
macro_rules! regfn_rw_union {
($block:ident, $reg:ident, $reg_name:expr, $uniontype:ident) => {
regfn_ro_union!($block, $reg, $reg_name, $uniontype);
regfn_wo_union!($block, $reg, $reg_name, $uniontype);
}
}
macro_rules! cpxmethod_ro {
($reg:ident, $datatype:ident) => {
pub fn $reg(&self) -> $datatype {
$reg()
}
}
}
macro_rules! cpxmethod_wo {
($reg:ident, $datatype:ident) => {
paste::paste! {
pub fn [<set_ $reg>](&self, data: $datatype) {
unsafe { [<set_ $reg>](data); }
}
}
}
}
macro_rules! cpxmethod_rw {
($reg:ident, $datatype:ident) => {
cpxmethod_ro!($reg, $datatype);
cpxmethod_wo!($reg, $datatype);
paste::paste! {
pub fn [<modify_ $reg>]<F: FnOnce($datatype) -> $datatype>(&self, func: F) {
unsafe { [<set_ $reg>](func($reg())); }
}
}
}
}
macro_rules! derive_tofrom_primitive {
($kind:ident, $prim:ident) => {
impl From<$prim> for $kind {
fn from(value: $prim) -> Self {
Self(value)
}
}
impl From<$kind> for $prim {
fn from(value: $kind) -> Self {
value.0
}
}
}
}
pub mod ai;
pub mod cp0;
pub mod cp1;
pub mod mi;
pub mod pi;
pub mod si;
pub mod vi;
pub struct RW<T: Copy>(T);
impl<T: Copy> RW<T> {
#[inline(always)]
pub fn read(&self) -> T {
unsafe { (&self.0 as *const T).read_volatile() }
}
#[inline(always)]
pub fn write(&self, data: T) {
unsafe { (&self.0 as *const T as *mut T).write_volatile(data); }
}
#[inline(always)]
pub fn modify<F: FnOnce(T) -> T>(&self, func: F) {
let ptr = &self.0 as *const T as *mut T;
unsafe { ptr.write_volatile(func(ptr.read_volatile())); }
}
}
pub struct RO<T: Copy>(T);
impl<T: Copy> RO<T> {
#[inline(always)]
pub fn read(&self) -> T {
unsafe { (&self.0 as *const T).read_volatile() }
}
}
pub struct WO<T: Copy>(T);
impl<T: Copy> WO<T> {
#[inline(always)]
pub fn write(&mut self, data: T) {
unsafe { (&mut self.0 as *mut T).write_volatile(data); }
}
}
static mut HARDWARE_TAKEN: bool = false;
pub struct Hardware {
pub cp0: Cp0,
pub cp1: Cp1,
pub mi: MipsInterface,
pub vi: VideoInterface,
pub ai: AudioInterface,
pub pi: PeripheralInterface,
pub si: SerialInterface,
}
impl Hardware {
#[inline]
pub fn take() -> Option<Self> {
if unsafe { HARDWARE_TAKEN } {
None
} else {
Some(unsafe { Self::steal() })
}
}
#[inline]
pub unsafe fn steal() -> Self {
HARDWARE_TAKEN = true;
Self {
cp0: Cp0::new(),
cp1: Cp1::new(),
mi: MipsInterface::new(),
vi: VideoInterface::new(),
ai: AudioInterface::new(),
pi: PeripheralInterface::new(),
si: SerialInterface::new(),
}
}
}