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

psx_gte/
lib.rs

1// SPDX-License-Identifier: GPL-2.0-or-later
2//! GTE (COP2) access -- PS1 Geometry Transformation Engine.
3//!
4//! The GTE isn't memory-mapped. It's MIPS coprocessor 2, accessed via
5//! a dedicated instruction class (`MTC2`/`MFC2`/`CTC2`/`CFC2` to move
6//! data between CPU and COP2 registers, `COP2 cofun` to run function
7//! ops like RTPS/RTPT/MVMVA/NCDS).
8//!
9//! This crate exposes two layers:
10//!
11//! - **Low-level register macros**: [`write_data!`], [`read_data!`],
12//!   [`write_control!`], [`read_control!`]. Each takes a literal
13//!   register index (0..31) so the assembler emits the correct
14//!   immediate field. Use these when you need direct access for
15//!   performance-sensitive paths.
16//!
17//! - **High-level operation wrappers**: zero-argument inline functions
18//!   for the common GTE commands with their typical options baked in
19//!   (e.g. [`ops::project_single`] uses `sf=1, lm=0`). On MIPS each
20//!   compiles to a single 4-byte `.word`. On host they dispatch to a per-thread
21//!   software GTE living in [`host`].
22//!
23//! All function-op wrappers are `unsafe fn` -- they assume the caller
24//! has loaded the required input registers via the register macros.
25//!
26//! # Same simulation, two backends
27//!
28//! - On `target_arch = "mips"` everything compiles down to direct
29//!   coprocessor instructions, identical to writing the assembly by
30//!   hand.
31//! - On host the macros and ops route through [`psx_gte_core::Gte`]
32//!   stored in a `thread_local!` cell. The simulation is the
33//!   bit-faithful one the emulator already runs against PCSX-Redux's
34//!   parity oracle, so editor previews match what the hardware draws.
35//!
36//! # Example
37//!
38//! ```ignore
39//! use psx_gte::{ops::project_single, read_data, write_control, write_data};
40//!
41//! unsafe {
42//!     write_control!(0, 0x0000_1000); // RT[0][0]=0x1000, RT[0][1]=0
43//!     // … fill in the rest of the rotation matrix and TR …
44//!     write_data!(0, (10 & 0xFFFF) | (20 << 16));
45//!     write_data!(1, 30);
46//!     project_single();
47//!     let sxy2: u32 = read_data!(14);
48//! }
49//! ```
50
51#![cfg_attr(target_arch = "mips", no_std)]
52#![deny(unsafe_op_in_unsafe_fn)]
53#![warn(missing_docs)]
54#![cfg_attr(target_arch = "mips", feature(asm_experimental_arch))]
55
56pub mod lighting;
57pub mod math;
58pub mod ops;
59pub mod regs;
60pub mod scene;
61pub mod transform;
62
63/// The COP2 instruction encodings the wrappers emit (`psx_hw::gte`).
64pub use psx_hw::gte as encoding;
65
66#[cfg(not(target_arch = "mips"))]
67pub mod host;