Crate n64_pac

Source
Expand description

Low-level hardware abstraction crate (aka a Peripheral Access Crate) for the Nintendo 64 console.

Unlike typical PACs, this API is not generated via svd2rust, as it doesn’t support the architecture and the N64 contains features not found on microcontrollers.

Additionally, while a singleton pattern is available to ensure safe access to hardware, helper functions are available that will bypass this pattern (static write/modify functions require unsafe).

§Singleton Pattern

Hardware is a top-level type that holds access to all available hardware abstractions. Using Hardware::take() a single instance of this abstraction can be taken, and if called a second time, None will be returned instead. This ensures safe, race-free, access to low level hardware.

If the developer wishes to bypass this pattern, such as in cases where interrupts are not used, or the developer has taken precautions against data races, they have several methods available.

§Direct hardware access

Both CPU registers and memory mapped registers have two methods of access outside the Hardware singleton type. Each method will usually optimize down to identical instructions.

§Static functions

Each module contains various read/modify/write functions for accessing hardware.

§Examples

Reads the VI_CTRL register, sets the pixel color depth to 32-bits, and writes it back to memory:

use n64_pac::vi;
use n64_pac::vi::ColorDepth;

let mut value = vi::ctrl();
value.set_depth(ColorDepth::BPP32);
unsafe {
    vi::set_ctrl(value);
}

Just like the above example, but using the modify function:

use n64_pac::vi;
use n64_pac::vi::ColorDepth;
 
unsafe {
    vi::modify_ctrl(|value| value.with_depth(ColorDepth::BPP32));
}
§Wrapper types

Memory mapped registers are accessed using mutable references that point to their location in memory. These references are wrapped into a struct for ease of use and so that blocks of registers can be automatically mapped using only a single pointer address.

CPU registers don’t use memory locations, but zero-sized structs exist anyways so that they can be accessed via the top-level Hardware abstraction.

It’s recommended to use the Static functions instead, as they implicitly use these wrappers, and will be optimized into the same instructions.

§Examples

Creates a wrapped pointer to the Video Interface’s block of registers, reads the VI_CTRL register, sets the pixel color depth to 32-bits, and writes it back to memory:

use n64_pac::vi::{ColorDepth, VideoInterface};

let vi = unsafe { VideoInterface::new() };
 
let mut value = vi.ctrl.read();
value.set_depth(ColorDepth::BPP32);
vi.ctrl.write(value);

Just like the above example, but using the modify method:

use n64_pac::vi::{ColorDepth, VideoInterface};

let vi = unsafe { VideoInterface::new() };
 
vi.ctrl.modify(|value| value.with_depth(ColorDepth::BPP32));

Modules§

ai
RCP - Audio Interface
cp0
CPU - Coprocessor 0
cp1
FPU - Coprocessor 1
mi
RCP - MIPS Interface
pi
RCP - Peripheral Interface
si
RCP - Serial Interface
vi
RCP - Video Interface

Structs§

Hardware
Represents all hardware abstractions.
RO
RW
WO