Skip to content
/ Raku Public

Homebrew for the N64 written in Rust

License

Notifications You must be signed in to change notification settings

xSetech/Raku

Repository files navigation

🏺 Raku

An ongoing experiment to build homebrew in Rust for the Nintendo 64.

Architecture

If you're unfamiliar with the console and its capabilities, see here:

Two MIPS III targets

The Nintendo 64 contains two MIPS III processors with significant differences between their architecture, lineage, and role within the system:

  1. The CPU, a "slightly modified" VR4300.
  2. 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.

Booting

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

Building

This section describes the requirements and process of building the Raku ROM.

Requirements

Rust

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).

Bash and Python

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+

LLVM

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).

How to build, end-to-end

An end-to-end build happens in two steps:

  1. ELF files are built by running cargo build -Z build-std=core in each crate directory.
  2. 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.

Testing

The generated ROM is currently tested in two ways:

This section is incomplete and will be expanded over time.

License

This work is available under the GNU General Public License v3.0 or later, see LICENSE.md