Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
e33b89f
Initial infra
alloncm May 3, 2025
d80ceac
Link with magenboy_nx
alloncm May 3, 2025
57fc2d2
WIP link rust to c
alloncm May 3, 2025
52f0979
Managed to write logs from rus
alloncm May 3, 2025
707ad28
Fix build and loaded rom
alloncm May 3, 2025
8dca6b8
Read files from C side
alloncm May 5, 2025
51b8c30
Add gfx device for nx
alloncm May 10, 2025
e334fd3
Add joycon support
alloncm May 10, 2025
3e997de
Add initial audio support for nx
alloncm May 10, 2025
36f4dc1
Improved sound quality
alloncm May 10, 2025
463035f
Fix audio issues
alloncm May 10, 2025
25c5737
Screen is now scaled using the switch scaler
alloncm May 22, 2025
0172161
Fix buttons and allow to load without nxlink
alloncm May 22, 2025
fbc529f
Add roms loading at start
alloncm May 23, 2025
4ceb1c9
Add mode detection
alloncm May 23, 2025
b6a121a
Revert back to rust 1.73
alloncm May 23, 2025
0e22033
Build using docker
alloncm May 24, 2025
c81641a
Add nx CI step
alloncm May 24, 2025
fb313c2
Move the docker file to the nx dir and arrange abit the build
alloncm May 24, 2025
2a3b2ef
Update readme with deps
alloncm May 24, 2025
244a771
WIP havent tested
alloncm May 24, 2025
9fb9ba2
I think I fixed the undefined behavior
alloncm May 31, 2025
32e3905
Fix menu navifation and add pause menu
alloncm Jun 7, 2025
118f21a
CR fixes + adding vscode settings to repo
alloncm Jun 7, 2025
565c458
Move to libm for float operations in core
alloncm Jun 7, 2025
d1c18c4
Format the C code
alloncm Jun 7, 2025
70de00d
Merge branch 'master' into feature/nx
alloncm Jun 7, 2025
7cf164c
Bump version to 4.2.0 and add version to header in pause
alloncm Jun 7, 2025
0349ca6
Add version and authors to the C app
alloncm Jun 21, 2025
d672e20
Fix warning and make the docker output plain + remove the version and…
alloncm Jun 21, 2025
2717a9a
Some minor fixes
alloncm Jun 21, 2025
90b91b5
Last fix
alloncm Jun 21, 2025
343833c
Add turbo factor to the nx
alloncm Jun 21, 2025
08467af
Add Nx docs
alloncm Jun 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*target/
.github/
docs/
*Dockerfile
6 changes: 5 additions & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,8 @@ jobs:
run: cargo make libretro_desktop

- name: Build libretro android
run: cargo make libretro_android
run: cargo make libretro_android

- name: Build nintendo switch
if: ${{ matrix.os == 'ubuntu-latest' }} # This fails on windows since it does not have docker installed
run: cargo make nx
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Dependencies/
*.bmp
*.img
*.txt
build/

## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
Expand Down Expand Up @@ -40,9 +41,6 @@ bld/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

#vscode
.vscode/

# Visual Studio 2017 auto generated files
Generated\ Files/

Expand Down
12 changes: 12 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"C_Cpp.default.includePath": [
"${DEVKITPRO}\\libnx\\include",
"${DEVKITPRO}\\devkitA64\\aarch64-none-elf\\include",
"${DEVKITPRO}\\devkitA64\\lib\\gcc\\aarch64-none-elf\\15.1.0\\include"
],
"rust-analyzer.cargo.extraEnv": {
"RPI": "4"
},
"rust-analyzer.cargo.allTargets": false,
"rust-analyzer.check.workspace": true,
}
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ members = [
"core",
"rpi",
"common",
"libretro"
"libretro",
"nx"
]

[workspace.package]
Expand Down
10 changes: 7 additions & 3 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ install_crate_args=["--locked", "--version", "0.2.5"]
command = "cross"
args = ["build", "--release", "--target", "armv7-unknown-linux-gnueabihf", "--bin", "rpios","--no-default-features", "--features", "os"]

[tasks.pre-rpibm]
[tasks.nightly-install]
command = "rustup"
args = ["toolchain", "install", "--profile", "minimal", "--no-self-update", "${nightly_version}"]

Expand All @@ -55,7 +55,7 @@ install_crate = "cargo-binutils"
install_crate_args=["--locked", "--version", "0.3.6"]
command = "rust-objcopy"
args = ["target/armv7a-none-eabihf/release/baremetal", "-O", "binary", "kernel7.img"]
dependencies = ["pre-rpibm", "build_rpi_baremetal","install_llvm_tools"]
dependencies = ["nightly-install", "build_rpi_baremetal","install_llvm_tools"]

[tasks.build_rpi_baremetal]
toolchain = "${nightly_version}"
Expand Down Expand Up @@ -85,4 +85,8 @@ dependencies = ["add_android_target"]

[tasks.add_android_target]
command = "rustup"
args = ["target", "add", "aarch64-linux-android"]
args = ["target", "add", "aarch64-linux-android"]

[tasks.nx]
command = "docker"
args = ["build", ".", "--file", "nx/Dockerfile", "--target", "export", "--output=.", "--build-arg", "NIGHTLY=${nightly_version}"]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Install `cargo-make`
```sh
cargo install cargo-make
```
verify you have docker or podman installed
Verify you have cmake and docker or podman installed

### Desktop

Expand Down
4 changes: 3 additions & 1 deletion common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ edition.workspace = true
magenboy_core = {path = "../core"}
log = "0.4"
cfg-if = "1"
libm = "0.2.15"
crossbeam-channel = {version = "0.5", optional = true}
fern = {version = "0.6", optional = true}
chrono = {version = "0.4", optional = true}

[features]
std = ["chrono", "fern", "crossbeam-channel"]
std = ["chrono", "fern", "crossbeam-channel", "alloc"]
dbg = ["std"]
alloc = []

[dev-dependencies]
criterion = "0.3"
Expand Down
2 changes: 2 additions & 0 deletions common/src/audio/audio_resampler.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use alloc::{string::String, vec::Vec};

use magenboy_core::apu::audio_device::{Sample, AudioDevice, StereoSample, BUFFER_SIZE};

pub trait AudioResampler{
Expand Down
14 changes: 9 additions & 5 deletions common/src/audio/manual_audio_resampler.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use alloc::vec::Vec;

use magenboy_core::apu::audio_device::{BUFFER_SIZE, StereoSample};
use super::audio_resampler::AudioResampler;

use super::audio_resampler::AudioResampler;

pub struct ManualAudioResampler{
to_skip:u32,
Expand All @@ -17,9 +19,11 @@ impl AudioResampler for ManualAudioResampler{
// Calling round in order to get the nearest integer and resample as precise as possible
let div = original_frequency as f32 / target_frequency as f32;

let lower_to_skip = div.floor() as u32;
let upper_to_skip = div.ceil() as u32;
let mut reminder = div.fract();
// Sicne we dont have many f32 methods without std we are implementing them ourself
let lower_to_skip = libm::floorf(div) as u32;
let upper_to_skip = libm::ceilf(div) as u32;
let mut reminder = div - (div as u32 as f32); // Acts as f32::fracts (since inputs are unsigned)

let (to_skip, alt_to_skip) = if reminder < 0.5{
(lower_to_skip, upper_to_skip)
}
Expand All @@ -29,7 +33,7 @@ impl AudioResampler for ManualAudioResampler{
};

if lower_to_skip == 0{
std::panic!("target freqency is too high: {}", target_frequency);
core::panic!("target freqency is too high: {}", target_frequency);
}

ManualAudioResampler{
Expand Down
10 changes: 8 additions & 2 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,24 @@ cfg_if::cfg_if!{ if #[cfg(feature = "std")] {
pub mod mbc_handler;
pub mod mpmc_gfx_device;
pub mod logging;
pub mod initialization;
pub use initialization::*;
}}

cfg_if::cfg_if!{ if #[cfg(feature = "alloc")] {
extern crate alloc;

pub mod audio{
mod audio_resampler;
mod manual_audio_resampler;
pub use audio_resampler::*;
pub use manual_audio_resampler::*;
}
pub mod initialization;
pub use initialization::*;
}}

pub mod menu;
pub mod joypad_menu;
pub mod interpolation;
pub mod synchronization;

pub const VERSION:&str = env!("MAGENBOY_VERSION");
2 changes: 2 additions & 0 deletions common/src/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ pub struct MenuOption<T, S:AsRef<str>>{
pub prompt:S
}

#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum EmulatorMenuOption{
Resume,
Restart,
Expand Down
File renamed without changes.
18 changes: 10 additions & 8 deletions core/src/utils/static_allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,22 @@ impl StaticAllocator{
}

pub fn alloc(&mut self, layout: Layout) -> NonNull<u8> {
let allocation_address = self.buffer_ptr as usize + self.allocation_size;
let aligned_address = Self::align_address(allocation_address, layout.align);
self.allocation_size += layout.size + (aligned_address - allocation_address);

if self.allocation_size > self.buffer_size{
if self.allocation_size + layout.align + layout.size > self.buffer_size {
core::panic!("Allocation failed, allocator is out of static memory, pool size: {}, allocation req: {}", self.buffer_size, layout.size);
}

let allocation_address = unsafe{self.buffer_ptr.add(self.allocation_size)};
let aligned_address = Self::align_address(allocation_address, layout.align);
self.allocation_size += layout.size + (unsafe{aligned_address.offset_from(allocation_address)} as usize);

return NonNull::new(aligned_address as *mut u8).expect("Null ptr detected");
}

fn align_address(address:usize, alignment:usize)->usize{
let reminder = address % alignment;
return if reminder != 0 {address - reminder + alignment} else {address};
fn align_address(address:*mut u8, alignment:usize)->*mut u8 {
let reminder = address as usize % alignment;
return if reminder != 0 {
unsafe{address.sub(reminder).add(alignment)}
} else {address};
}
}

Expand Down
16 changes: 16 additions & 0 deletions nx/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "magenboy_nx"
edition.workspace = true
version.workspace = true
authors.workspace = true
rust-version.workspace = true

[lib]
crate-type = ["staticlib"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
magenboy_core = { path = "../core", features = ["apu"] }
magenboy_common = { path = "../common", features = ["alloc"] }
log = "0.4"
32 changes: 32 additions & 0 deletions nx/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# We are installing the Rust toolchain so the version does not matter
FROM rust:latest AS builder

# Nightly version - entered as a build argument
ARG NIGHTLY

RUN rustup toolchain install ${NIGHTLY}
RUN rustup +${NIGHTLY} component add rust-src

WORKDIR /magenboy

COPY . .

RUN cargo +${NIGHTLY} build --release --package magenboy_nx --target aarch64-nintendo-switch-freestanding \
-Z build-std=core,compiler_builtins,alloc -Z build-std-features=compiler-builtins-mem

# Use the devkitpro/devkita64 image for the second stage
FROM devkitpro/devkita64 AS final

WORKDIR /magenboy_nx

COPY nx/Makefile ./
COPY nx/src ./src

# Copy the built Rust library from the builder stage
COPY --from=builder /magenboy/target/ ./target/

RUN make --always-make

# Export the built files using a scratch image, this is the best praactice for multi-stage builds
FROM scratch AS export
COPY --from=final /magenboy_nx/build/ /target
Loading
Loading