An ongoing experiment to build homebrew in Rust for the Nintendo 64.
If you're unfamiliar with the console and its capabilities, see here:
- https://www.copetti.org/writings/consoles/nintendo-64/
- https://github.com/command-tab/awesome-n64-development
The Nintendo 64 contains two MIPS III processors with significant differences between their architecture, lineage, and role within the system:
- The CPU, a "slightly modified" VR4300.
- The RCP, a heavily modified R4000 that uses a 32-bit ISA optimized for vector math and graphics rendering. Unlike the CPU, it lacks a floating point coprocessor, caches, and exceptions.
Crates in this repo compile to code targeting one of those processors. The
details of each target (e.g. stack alignment requirements, pointer width, etc)
are specified in the targets/
subdirectory within JSON
"target specification" files.
The bootloader crate contains code called after completion of the IPL2 startup stage. This program is typically called "IPL3", but differs significantly from other IPL3 payloads in function and implementation.
The Raku bootloader performs two functions:
- Very basic hardware initialization: interrupt silencing and RDRAM configuration.
- Copying of kernel code and data sections from the ROM, followed by kernel entry.
It tries to meet these design goals:
- Do least amount of work to enter the kernel
- Payload fits in ~4k bytes after optimization
- No dependencies on external crates or code
- Heavily commented
- No stack use
This section describes the requirements and process of building the Raku ROM.
This is a project written in Rust and built with the standard Rust toolchain (i.e. Cargo). Follow the instructions at rust-lang.org to install Rust and Cargo.
The project is built using a specific version of the Rust compiler; it's
specified in rust-toolchain.toml
. Cargo should
automatically pull down this version for your system at build time. If you'd
like to experiment with different versions of Rust, you must use at least
nightly-2023-07-14 (which contains a patch related the N32 ABI).
The ROM is assembled from compiled crates by shell and Python scripts located in scripts/
.
Given that, Bash and Python must be installed. The project was initially built using these
versions; other versions probably work, but they're left here for clarity:
- Bash 3.2+
- Python 3.10+
The project is developed and debugged using LLVM 16 tools. lld
is used for
linking and llvm-objdump
is used to extract the .text section from the
bootloader (although objdump
from GNU Binutils could probably suffice for the
same purpose).
An end-to-end build happens in two steps:
- ELF files are built by running
cargo build -Z build-std=core
in each crate directory. - A ROM (.z64) is formed from via
assemble-rom.sh
This script handles everything end-to-end, assuming the build requirements are met:
scripts/build-release.sh
.
If all goes well, a ROM will be present in a directory named target/
(generated by the build process). Look for a file with a .z64
extension.
The generated ROM is currently tested in two ways:
- Virtually, via a modified fork of Ares
- On the metal, via an EverDrive-64 X7
This section is incomplete and will be expanded over time.
This work is available under the GNU General Public License v3.0 or later, see LICENSE.md