n64-pac 0.1.0

Provides low-level CPU and register abstractions for the Nintendo 64 console
use core::ops::Deref;
use num_enum::{FromPrimitive, IntoPrimitive};
use proc_bitfield::bitfield;
use crate::RW;

/// Pointer to the Video Interface's memory mapped registers.
pub struct VideoInterface {
    r: &'static mut RegisterBlock,
}

#[repr(C)]
pub struct RegisterBlock {
    pub ctrl: RW<CtrlReg>,
    pub origin: RW<u32>,
    pub width: RW<u32>,
    pub v_intr: RW<u32>,
    pub burst: RW<BurstReg>,
    pub v_sync: RW<u32>,
    pub h_sync: RW<HSyncReg>,
    pub h_sync_leap: RW<HSyncLeapReg>,
    pub h_video: RW<HVideoReg>,
    pub v_video: RW<VVideoReg>,
    pub v_burst: RW<VBurstReg>,
    pub x_scale: RW<XScaleReg>,
    pub y_scale: RW<YScaleReg>,
    pub test_addr: RW<u32>,
    pub staged_data: RW<u32>,
}
regfn_rw!(VideoInterface, ctrl, CTRL, CtrlReg);
regfn_rw!(VideoInterface, origin, ORIGIN, u32);
regfn_rw!(VideoInterface, width, WIDTH, u32);
regfn_rw!(VideoInterface, v_intr, V_INTR, u32);
regfn_rw!(VideoInterface, burst, BURST, BurstReg);
regfn_rw!(VideoInterface, v_sync, V_SYNC, u32);
regfn_rw!(VideoInterface, h_sync, H_SYNC, HSyncReg);
regfn_rw!(VideoInterface, h_sync_leap, H_SYNC_LEAP, HSyncLeapReg);
regfn_rw!(VideoInterface, h_video, H_VIDEO, HVideoReg);
regfn_rw!(VideoInterface, v_video, V_VIDEO, VVideoReg);
regfn_rw!(VideoInterface, v_burst, V_BURST, VBurstReg);
regfn_rw!(VideoInterface, x_scale, X_SCALE, XScaleReg);
regfn_rw!(VideoInterface, y_scale, Y_SCALE, YScaleReg);
regfn_rw!(VideoInterface, test_addr, TEST_ADDR, u32);
regfn_rw!(VideoInterface, staged_data, STAGED_DATA, u32);

impl VideoInterface {
    /// Creates a new mutable pointer to the Video Interface's memory mapped registers, starting at `0xA4400000`.
    /// 
    /// # Safety
    /// You may create as many of these instances as you wish. Just note that if used in both normal
    /// code, and within an interrupt handler/callback, unexpected could potentially occur if the
    /// interrupt occurs during a read-modify-write operation.
    #[inline(always)]
    pub fn new() -> Self { Self {
        r: unsafe { &mut *(0xA4400000 as *mut RegisterBlock) }
    }}
}
impl Deref for VideoInterface {
    type Target = RegisterBlock;

    fn deref(&self) -> &Self::Target {
        self.r
    }
}


#[derive(IntoPrimitive, FromPrimitive, Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum AntiAliasMode {
    Disabled = 3,
    ResamplingOnly = 2,
    EnabledAsNeeded = 1,
    #[default]
    Enabled = 0,
}

#[derive(IntoPrimitive, FromPrimitive, Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum ColorDepth {
    BPP32 = 3,
    BPP16 = 2,
    Reserved = 1,
    #[default]
    Blank = 0,
}

bitfield! {
    #[derive(Copy, Clone, PartialEq, Eq)]
    pub struct CtrlReg(pub u32): Debug {
        pub depth: u8 [ColorDepth] @ 0..=1,
        pub gamma_dither_enable: bool @ 2,
        pub gamma_enable: bool @ 3,
        pub divot_enable: bool @ 4,
        /// # Safety:
        /// **Never** enable this bit! Early research indicates this could potentially damage the console if set to `true`.
        pub vbus_clock_enable: bool @ 5,
        pub serrate: bool @ 6,
        pub test_mode: bool @ 7,
        pub aa_mode: u8 [AntiAliasMode] @ 8..=9,
        pub kill_we: bool @ 11,
        pub pixel_advance: u8 @ 12..=15,
        pub dither_filter_enable: bool @ 16,
    }
}

bitfield! {
    #[derive(Copy, Clone, PartialEq, Eq)]
    pub struct BurstReg(pub u32): Debug {
        pub hsync_width: u8 @ 0..=7,
        pub burst_width: u8 @ 8..=15,
        pub vsync_width: u8 @ 16..=19,
        pub burst_start: u16 @ 20..=29,
    }
}

bitfield! {
    #[derive(Copy, Clone, PartialEq, Eq)]
    pub struct HSyncReg(pub u32): Debug {
        pub h_sync: u16 @ 0..=11,
        pub leap: u8 @ 16..=20,
    }
}

bitfield! {
    #[derive(Copy, Clone, PartialEq, Eq)]
    pub struct HSyncLeapReg(pub u32): Debug {
        pub leap_b: u16 @ 0..=9,
        pub leap_a: u16 @ 16..=25,
    }
}

bitfield! {
    #[derive(Copy, Clone, PartialEq, Eq)]
    pub struct HVideoReg(pub u32): Debug {
        pub h_end: u16 @ 0..=9,
        pub h_start: u16 @ 16..=25,
    }
}

bitfield! {
    #[derive(Copy, Clone, PartialEq, Eq)]
    pub struct VVideoReg(pub u32): Debug {
        pub v_end: u16 @ 0..=9,
        pub v_start: u16 @ 16..=25,
    }
}

bitfield! {
    #[derive(Copy, Clone, PartialEq, Eq)]
    pub struct VBurstReg(pub u32): Debug {
        pub v_burst_end: u16 @ 0..=9,
        pub v_burst_start: u16 @ 16..=25,
    }
}

bitfield! {
    #[derive(Copy, Clone, PartialEq, Eq)]
    pub struct XScaleReg(pub u32): Debug {
        pub x_scale: u16 @ 0..=11,
        pub x_offset: u16 @ 16..=27,
    }
}

bitfield! {
    #[derive(Copy, Clone, PartialEq, Eq)]
    pub struct YScaleReg(pub u32): Debug {
        pub y_scale: u16 @ 0..=11,
        pub y_offset: u16 @ 16..=27,
    }
}