Skip to main content
← PSoXide SDK guides and examples · SDK f2fec1c301f1 · All Cargo features enabled; check feature gates before use.

psx_io/
lib.rs

1// SPDX-License-Identifier: GPL-2.0-or-later
2//! Volatile MMIO primitives.
3//!
4//! The lowest layer of the SDK. Wraps `core::ptr::read_volatile` /
5//! `write_volatile` in zero-overhead helpers that each peripheral
6//! module builds on. Keeping these centralised means we can audit
7//! every MMIO touchpoint in one file.
8//!
9//! All functions here are `#[inline(always)]` and `unsafe` -- they
10//! accept arbitrary addresses and widths. Higher-level SDK crates
11//! present safe APIs on top of these.
12
13#![no_std]
14#![cfg_attr(target_arch = "mips", feature(asm_experimental_arch))]
15#![deny(unsafe_op_in_unsafe_fn)]
16#![warn(missing_docs)]
17
18pub mod cd;
19pub mod cdda;
20pub mod cdrom;
21pub mod controller_port;
22pub mod disc_base;
23pub mod dma;
24pub mod gpu;
25pub mod irq;
26pub mod periph;
27pub mod timers;
28
29/// Read a 32-bit word from `addr`. Caller must guarantee `addr` is
30/// valid MMIO for a 32-bit read.
31///
32/// # Safety
33/// Targets unchecked memory-mapped I/O. The caller is responsible for
34/// the address mapping and any side effects.
35#[inline(always)]
36pub unsafe fn read_u32(addr: u32) -> u32 {
37    // SAFETY: the caller guarantees `addr` is mapped and valid for an aligned 32-bit volatile read
38    // (this fn's `# Safety`).
39    unsafe { core::ptr::read_volatile(addr as *const u32) }
40}
41
42/// Read a 16-bit half-word from `addr`.
43///
44/// # Safety
45/// See [`read_u32`].
46#[inline(always)]
47pub unsafe fn read_u16(addr: u32) -> u16 {
48    // SAFETY: the caller guarantees `addr` is mapped and valid for an aligned 16-bit volatile read
49    // (this fn's `# Safety`).
50    unsafe { core::ptr::read_volatile(addr as *const u16) }
51}
52
53/// Read an 8-bit byte from `addr`.
54///
55/// # Safety
56/// See [`read_u32`].
57#[inline(always)]
58pub unsafe fn read_u8(addr: u32) -> u8 {
59    // SAFETY: the caller guarantees `addr` is mapped and valid for an 8-bit volatile read (this
60    // fn's `# Safety`).
61    unsafe { core::ptr::read_volatile(addr as *const u8) }
62}
63
64/// Write a 32-bit word to `addr`.
65///
66/// # Safety
67/// See [`read_u32`].
68#[inline(always)]
69pub unsafe fn write_u32(addr: u32, value: u32) {
70    // SAFETY: the caller guarantees `addr` is mapped and valid for an aligned 32-bit volatile write
71    // (this fn's `# Safety`).
72    unsafe { core::ptr::write_volatile(addr as *mut u32, value) }
73}
74
75/// Write a 16-bit half-word to `addr`.
76///
77/// # Safety
78/// See [`read_u32`].
79#[inline(always)]
80pub unsafe fn write_u16(addr: u32, value: u16) {
81    // SAFETY: the caller guarantees `addr` is mapped and valid for an aligned 16-bit volatile write
82    // (this fn's `# Safety`).
83    unsafe { core::ptr::write_volatile(addr as *mut u16, value) }
84}
85
86/// Write an 8-bit byte to `addr`.
87///
88/// # Safety
89/// See [`read_u32`].
90#[inline(always)]
91pub unsafe fn write_u8(addr: u32, value: u8) {
92    // SAFETY: the caller guarantees `addr` is mapped and valid for an 8-bit volatile write (this
93    // fn's `# Safety`).
94    unsafe { core::ptr::write_volatile(addr as *mut u8, value) }
95}
96
97/// Renamed to [`read_u8`].
98///
99/// # Safety
100/// See [`read_u8`].
101#[deprecated(note = "renamed to `read_u8`")]
102#[inline(always)]
103pub unsafe fn read8(addr: u32) -> u8 {
104    // SAFETY: same contract as the renamed function.
105    unsafe { read_u8(addr) }
106}
107
108/// Renamed to [`write_u8`].
109///
110/// # Safety
111/// See [`write_u8`].
112#[deprecated(note = "renamed to `write_u8`")]
113#[inline(always)]
114pub unsafe fn write8(addr: u32, value: u8) {
115    // SAFETY: same contract as the renamed function.
116    unsafe { write_u8(addr, value) }
117}