Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Newlib binary and allocator support #20

Closed
wants to merge 7 commits into from
Closed

Add Newlib binary and allocator support #20

wants to merge 7 commits into from

Conversation

ghost
Copy link

@ghost ghost commented Feb 20, 2020

Adds builds of newlib-3.3.0, and implement an allocator in n64lib which
uses this.

Newlib was built as follows:

CFLAGS_FOR_TARGET="-DPREFER_SIZE_OVER_SPEED=1 -Os -G0 -mabi=32 -mno-gpopt" \
    ../configure --target=mips-elf

libc.a and libm.a are bundled in the cargo-n64 executable, and written
to the temp directory where the other temporary build artifacts are
placed (linker script, for example).

Since our sbrk() starts returning memory at the end of the .bss section,
up the alignment of this in the linker script to 16 bytes.

Also enable the 'noabicalls' feature in the target.json. This is the
default in GCC with the mips-elf target, but not for LLVM. The linker
will emit some warnings without this.

Adds builds of newlib-3.3.0, and implement an allocator in n64lib which
uses this.

Newlib was configured as follows:

    CFLAGS_FOR_TARGET="-DPREFER_SIZE_OVER_SPEED=1 -Os -G0 -mabi=32 -mno-gpopt" \
        ../configure --target=mips-elf

libc.a and libm.a are bundled in the cargo-n64 executable, and written
to the temp directory where the other temporary build artifacts are
placed (linker script, for example).

Since our sbrk() starts returning memory at the end of the .bss section,
up the alignment of this in the linker script to 16 bytes.

Also enable the 'noabicalls' feature in the target.json. This is the
default in GCC with the mips-elf target, but not for LLVM. The linker
will emit some warnings without this.
@parasyte
Copy link
Collaborator

parasyte commented Feb 21, 2020

Clippy is pretty unhappy with this one. We have a couple of options:

  1. Add #[cfg(target_vendor = "nintendo64")] in a lot of places. Like this.
  2. Split the N64 code out of this repo (Find a better way to organize the example(s) #6)

@ghost
Copy link
Author

ghost commented Feb 25, 2020

  1. #[cfg(target_vendor = "nintendo64")]

I went with this, as it's the easiest option for the time being.

Should return the previous pointer, rather than the incremented one.
@ghost
Copy link
Author

ghost commented Feb 26, 2020

Had to fix the sbrk implementation, turns out it was wrong. Reference implementation from newlib.

@parasyte
Copy link
Collaborator

Is this ready for review?

@ghost
Copy link
Author

ghost commented Feb 27, 2020

Yes, it's ready. I tested it yesterday by modifying the hello world example to use a format!()'d string rather than a constant, and verifying that malloc was being called.

@ghost
Copy link
Author

ghost commented Feb 27, 2020

Actually, just hold off on this for now... I'm seeing some strange behavior when I'm trying to allocate frame buffers using malloc. The _gp symbol is present (and points to something), despite newlib being compiled with -mno-gpopt. And what's weirder is I can't find the _gp symbol anywhere in libc.a. Maybe it's from llvm.

cargo-n64/src/cli.rs Outdated Show resolved Hide resolved
examples/n64lib/src/allocator.rs Outdated Show resolved Hide resolved
examples/n64lib/src/allocator.rs Outdated Show resolved Hide resolved
unsafe {
asm!("
mtc0 $0,$$12"
// todo: Hazards? Two nops after this? ^
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question... I'd have to go back over the MIPS docs to answer this, myself. But IIRC the instruction pipeline will be stalled in the presence of hazards, but shouldn't cause undefined behavior?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs say:

The hazard related to CP0 does not generate the interlock of the
pipeline. Therefore, control the number of required instructions
by program.

They also say:

The number of NOP instructions between the instructions related to the CP0
register and TLB, or the number of the instructions independent of the conflict can
be calculated from the following expression, using this table.
(Number of destination hazards of instruction A) - {(Number of source hazards of instruction B) +1}

And then they present an example:

As an example, to find the number of instructions required between an MTC0 and
a subsequent MFC0 instruction, this is:
(7) - (4 + 1) = 2 instructions

The table they refer to is on page 621 of this document: http://datasheets.chipdb.org/NEC/Vr-Series/Vr43xx/U10504EJ7V0UMJ1.pdf

So, maybe 2 nops would be enough?

@parasyte
Copy link
Collaborator

@kskjer FWIW the Nintendo64 target compiles with static relocation model to workaround problems I had with the global pointer:

"relocation-model": "static",

/*
* We may need the global offset table some day.
* Our target is currently set with a static relocation-model, so this
* might not be needed after all.
*/
*(.got)

I suspect libc and libm need to be compiled with a fairly similar ABI.

@ghost
Copy link
Author

ghost commented Feb 29, 2020

@kskjer FWIW the Nintendo64 target compiles with static relocation model to workaround problems I had with the global pointer:

"relocation-model": "static",

/*
* We may need the global offset table some day.
* Our target is currently set with a static relocation-model, so this
* might not be needed after all.
*/
*(.got)

I suspect libc and libm need to be compiled with a fairly similar ABI.

Yeah, turns out the _gp sym was a red herring, and it's always there (but not used) if an .sdata section is present. The issue was that the CRCs were wrong due to a bug in my padding PR. The ABI configured in the target.json and what newlib was compiled with should be the same.

@JoNil
Copy link
Contributor

JoNil commented May 2, 2020

Hi!

One alternate approach to an allocator is the one i built here: https://github.com/JoNil/loka-n64/tree/master/n64-alloc

It is basically a copy of https://crates.io/crates/wee_alloc for webassembly but with only the static array backend.

Cheers

@parasyte
Copy link
Collaborator

parasyte commented May 4, 2020

That's really cool! Thanks for sharing the link. I see you also have some other interesting stuff floating around in there...

I am also interested in experimenting with drone. I don't think it's an exact fit, but there's a lot of interesting things in it already. As much as I love building kernels, I would like someone else to do the heavy lifting. 😂

@parasyte parasyte changed the base branch from master to main December 28, 2020 22:52
@ghost ghost closed this by deleting the head repository Jan 26, 2023
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants