Skip to content

Commit 36689ce

Browse files
authored
Use open-source ipl3 (#68)
* Use open source ipl3-prod * Remove emux instruction at boot * Change comment * Update physical_cart_address to reflect what the new ipl3 does * Clear MI Interrupt mask at boot The new ipl3 keeps the mask at non-0, which causes an interrupt to be signalled in Cause. Clear it at boot to ensure things are all as expected. * Bump version number * Read ramsize from ipl3 instead of auto-detecting * Remove emux in boot.s * Completely remove boot.asm - with the new ipl3, the bootup can be done in 100% Rust * Remove boot.asm; determine rom offset; update build instructions - boot.asm isn't need anymore - the little hardware we still need we can do in Rust. - rom offset: ipl3 puts the value we need into SPMEM. Use that instead of hardcoding
1 parent 8eaa398 commit 36689ce

File tree

12 files changed

+124
-214
lines changed

12 files changed

+124
-214
lines changed

.cargo/config.toml

+1-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,5 @@ build-std = ["core", "alloc"]
88
rustflags = ["-Clinker-plugin-lto"]
99

1010
# runner specifies a program that cargo automatically executes after compiling (using the 'cargo run' command).
11-
# nust64 is used by default, to convert the generated ELF file into an N64 ROM, including the provided IPL3 binary.
12-
# If you wish to use a different IPL3 file, just provide its path here, in place of the mini-ipl3.
1311
# Cargo will append this command with the path to the ELF file, so make sure the command ends with '--elf'.
14-
runner = "nust64 --ipl3 mini-ipl3/mini-ipl3.bin --elf"
12+
runner = "nust64 --elf"

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "n64-systemtest"
3-
version = "2.0.5"
3+
version = "2.1.0"
44
edition = "2021"
55

66
[features]
@@ -30,7 +30,7 @@ cop0hazard = ["quick"]
3030

3131
# Tests that show something weird about the hardware where the pattern isn't fully understood. These tests aren't enough
3232
# to implement in an emulator yet. As more tests for a certain quirk are being written (and the understanding grows),
33-
# they'd move out of this category. Therefore it is disabled by default and not even reported as disabled.
33+
# they'd move out of this category. Therefore, it is disabled by default and not even reported as disabled.
3434
poorly_understood_quirk = ["quick"]
3535

3636
vmulf_stress_test = []

README.md

-4
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ cargo install nust64
3131
```
3232
4. Run `cargo run --release` to build the test rom.
3333

34-
**Please note:** N64 roms require a bootcode called IPL3. This bootcode is expected to setup hardware and copy the rom into memory. n64-systemtest comes with its own IPL3, which will **NOT** run on hardware. Once there is a community built open-source IPL3, we'll switch to that.
35-
36-
If you'd like to use your own IPL3: Reconfigure the IPL3 path used by the runner (nust64) in `.cargo/config.toml`.
37-
3834
# Expanded test-set
3935
In addition to the regular set of tests, n64-systemtest has a few additional sets which can
4036
be enabled individually: timing, cycle and cop0hazard. Refer to cargo.toml for a detailed description.

linker.ld

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
ENTRY(_start)
1+
ENTRY(entrypoint)
22

33
SECTIONS {
44
. = 0x80000400;

mini-ipl3/mini-ipl3.bin

-3.94 KB
Binary file not shown.

mini-ipl3/mini-ipl3.s

-112
This file was deleted.

src/boot.s

-72
This file was deleted.

src/main.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@
1919

2020
extern crate alloc;
2121

22-
use core::arch::global_asm;
23-
22+
use crate::cop1::FCSR;
2423
use spinning_top::Spinlock;
24+
use crate::cop1::set_fcsr;
2525
use crate::graphics::framebuffer_console::FramebufferConsole;
2626

2727
use crate::graphics::vi::Video;
2828
use crate::memory_map::MemoryMap;
29+
use crate::rsp::spmem::SPMEM;
2930

3031
mod allocator;
3132
mod assembler;
@@ -45,13 +46,20 @@ mod rsp;
4546
mod tests;
4647
mod uncached_memory;
4748

48-
global_asm!(include_str!("boot.s"));
49-
5049
static VIDEO: Spinlock<Video> = Spinlock::new(Video::new());
5150

5251
#[no_mangle]
53-
unsafe extern "C" fn rust_entrypoint() -> ! {
54-
MemoryMap::init();
52+
unsafe extern "C" fn entrypoint() -> ! {
53+
// IPL3 (the bootloader) write the memory size to DMEM. We can read it from there
54+
let memory_size = SPMEM::read(0) as usize;
55+
let elf_header_offset = ((SPMEM::read(12) >> 16) << 8) as usize;
56+
MemoryMap::init(memory_size, elf_header_offset);
57+
58+
// fcsr isn't reset on boot. Use a good default for the main loop - some tests will change and
59+
// restore this
60+
set_fcsr(FCSR::new().with_flush_denorm_to_zero(true).with_enable_invalid_operation(true));
61+
62+
mi::clear_interrupt_mask();
5563
allocator::init_allocator();
5664
main();
5765

src/memory_map.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// growing down from the end: stack
55

66
static mut MEMORY_SIZE: usize = 0;
7+
static mut ELF_HEADER_OFFSET: usize = 0;
78

89
pub struct MemoryMap {
910

@@ -17,11 +18,11 @@ impl MemoryMap {
1718
pub const PHYSICAL_PIFRAM_BASE: usize = 0x1FC0_07C0;
1819

1920
/// Call very early (before setting up exception handlers) during boot to set memory size
20-
pub(super) fn init() {
21+
pub(super) fn init(memory_size: usize, elf_header_offset: usize) {
2122
assert_eq!(Self::memory_size(), 0);
2223
unsafe {
23-
let value = *(0x8000_0318 as *mut usize);
24-
MEMORY_SIZE = value;
24+
MEMORY_SIZE = memory_size;
25+
ELF_HEADER_OFFSET = elf_header_offset;
2526
};
2627
}
2728

@@ -31,6 +32,12 @@ impl MemoryMap {
3132
unsafe { MEMORY_SIZE }
3233
}
3334

35+
/// Returns the number of bytes that the elf header is offset RAM vs ROM
36+
pub fn elf_header_offset() -> usize {
37+
// MEMORY_SIZE is only set during early boot and then never again, so this should be safe
38+
unsafe { ELF_HEADER_OFFSET }
39+
}
40+
3441
/// Returns an uncached pointer of the given pointer (e.g. 0xA000_1234 is returned for 0x8000_1234
3542
pub fn uncached<T>(p: *const T) -> *const T {
3643
let memory_address = p as usize;
@@ -46,13 +53,13 @@ impl MemoryMap {
4653

4754
/// Returns the cartridge (rom) address of a given constant
4855
pub fn physical_cart_address<T>(p: *const T) -> usize {
49-
// The bootcode copies from 0x10001000 to 0x8000_0400. If we have some other pointer,
56+
// The bootcode copies from ROM to 0x8000_0400. If we have some other pointer,
5057
// it doesn't come from the cart
5158
let memory_address = p as usize;
5259
assert!(memory_address >= 0x8000_0400);
5360
assert!(memory_address < 0x8000_0400 + 3 * 1024 * 1024);
5461

55-
memory_address - 0x8000_0000 + 0x10001000 - 0x400
62+
memory_address - 0x8000_0000 + 0x10000000 + MemoryMap::elf_header_offset()
5663
}
5764

5865
pub fn uncached_cart_address<T>(p: *const T) -> *const T {

0 commit comments

Comments
 (0)