From e966763fed191d861fe3ab98cb9b905c99a3ce66 Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Sun, 2 Nov 2025 19:29:17 -0700 Subject: [PATCH] runnintg --- .gitmodules | 6 +- Cargo.lock | 20 ++-- Cargo.toml | 2 +- justfile | 4 +- user-apps/{nes => gboy}/Cargo.toml | 2 +- user-apps/{nes => gboy}/Peanut-GB | 0 user-apps/{nes => gboy}/build.rs | 9 ++ user-apps/{nes => gboy}/peanut_gb_stub.c | 0 user-apps/gboy/src/main.rs | 116 +++++++++++++++++++++++ user-apps/gboy/src/peanut.rs | 85 +++++++++++++++++ user-apps/nes/src/main.rs | 88 ----------------- user-apps/nes/src/peanut.rs | 45 --------- 12 files changed, 228 insertions(+), 149 deletions(-) rename user-apps/{nes => gboy}/Cargo.toml (92%) rename user-apps/{nes => gboy}/Peanut-GB (100%) rename user-apps/{nes => gboy}/build.rs (83%) rename user-apps/{nes => gboy}/peanut_gb_stub.c (100%) create mode 100644 user-apps/gboy/src/main.rs create mode 100644 user-apps/gboy/src/peanut.rs delete mode 100644 user-apps/nes/src/main.rs delete mode 100644 user-apps/nes/src/peanut.rs diff --git a/.gitmodules b/.gitmodules index eeb39fc..26531ce 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ -[submodule "user-apps/nes/Peanut-GB"] - path = user-apps/nes/Peanut-GB - url = https://github.com/deltabeard/Peanut-GB [submodule "picolibc"] path = picolibc url = https://github.com/picolibc/picolibc +[submodule "user-apps/gboy/Peanut-GB"] + path = user-apps/gboy/Peanut-GB + url = https://github.com/deltabeard/Peanut-GB diff --git a/Cargo.lock b/Cargo.lock index c24ba83..19c302d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1306,6 +1306,16 @@ dependencies = [ "tinybmp", ] +[[package]] +name = "gboy" +version = "0.1.0" +dependencies = [ + "abi", + "bindgen", + "cc", + "embedded-graphics", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1753,16 +1763,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" -[[package]] -name = "nes" -version = "0.1.0" -dependencies = [ - "abi", - "bindgen", - "cc", - "embedded-graphics", -] - [[package]] name = "new_debug_unreachable" version = "1.0.6" diff --git a/Cargo.toml b/Cargo.toml index 4cc1e48..e370f22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ "user-apps/snake", "user-apps/gallery", "user-apps/gif", - "user-apps/nes", + "user-apps/gboy", ] [profile.release] diff --git a/justfile b/justfile index 978257d..fee1f63 100644 --- a/justfile +++ b/justfile @@ -1,5 +1,7 @@ kernel-dev board: cargo run --bin kernel --features {{board}} +kernel-release-probe board: + cargo run --bin kernel --profile release --features {{board}} kernel-release board: cargo build --bin kernel --release --no-default-features --features {{board}} elf2uf2-rs -d target/thumbv8m.main-none-eabihf/release/kernel @@ -37,4 +39,4 @@ userapps: cbindgen just userapp snake just userapp gallery just userapp gif - just userapp nes + just userapp gboy diff --git a/user-apps/nes/Cargo.toml b/user-apps/gboy/Cargo.toml similarity index 92% rename from user-apps/nes/Cargo.toml rename to user-apps/gboy/Cargo.toml index b3f0e18..184cec7 100644 --- a/user-apps/nes/Cargo.toml +++ b/user-apps/gboy/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "nes" +name = "gboy" version = "0.1.0" edition = "2024" diff --git a/user-apps/nes/Peanut-GB b/user-apps/gboy/Peanut-GB similarity index 100% rename from user-apps/nes/Peanut-GB rename to user-apps/gboy/Peanut-GB diff --git a/user-apps/nes/build.rs b/user-apps/gboy/build.rs similarity index 83% rename from user-apps/nes/build.rs rename to user-apps/gboy/build.rs index 3e33d7d..1425720 100644 --- a/user-apps/nes/build.rs +++ b/user-apps/gboy/build.rs @@ -47,6 +47,15 @@ fn bindgen() { cc::Build::new() .file("peanut_gb_stub.c") .include("Peanut-GB") + // optimization flags + .flag("-O3") // max optimization + .flag("-ffast-math") // faster floating point, if any + .flag("-funroll-loops") // unroll small loops + // CPU/architecture flags (example for ARM Cortex-M33) + .flag("-mcpu=cortex-m33") + .flag("-mthumb") + // optional: strip debug info + .flag("-g0") .compile("peanut_gb"); println!("cargo:rustc-link-search=Peanut-GB"); diff --git a/user-apps/nes/peanut_gb_stub.c b/user-apps/gboy/peanut_gb_stub.c similarity index 100% rename from user-apps/nes/peanut_gb_stub.c rename to user-apps/gboy/peanut_gb_stub.c diff --git a/user-apps/gboy/src/main.rs b/user-apps/gboy/src/main.rs new file mode 100644 index 0000000..dc17bd4 --- /dev/null +++ b/user-apps/gboy/src/main.rs @@ -0,0 +1,116 @@ +#![no_std] +#![no_main] +#![allow(static_mut_refs)] + +extern crate alloc; +use abi::{ + Rng, + display::{Display, SCREEN_HEIGHT, SCREEN_WIDTH}, + fs::{file_len, read_file}, + get_key, + keyboard::{KeyCode, KeyState}, + print, sleep, +}; +use alloc::{vec, vec::Vec}; +use core::{cell::LazyCell, ffi::c_void, mem::MaybeUninit, panic::PanicInfo}; +use embedded_graphics::{pixelcolor::Rgb565, prelude::RgbColor}; + +mod peanut; +use peanut::gb_run_frame; + +use crate::peanut::{ + gb_cart_ram_read, gb_cart_ram_write, gb_error, gb_init, gb_init_lcd, gb_rom_read, gb_s, + lcd_draw_line, +}; + +static mut DISPLAY: Display = Display; + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + print!("user panic: {} @ {:?}", info.message(), info.location(),); + loop {} +} + +#[unsafe(no_mangle)] +pub extern "Rust" fn _start() { + main() +} + +const PEANUT_A: u8 = 0x01; +const PEANUT_B: u8 = 0x02; +const PEANUT_SELECT: u8 = 0x04; +const PEANUT_START: u8 = 0x08; +const PEANUT_RIGHT: u8 = 0x10; +const PEANUT_LEFT: u8 = 0x20; +const PEANUT_UP: u8 = 0x40; +const PEANUT_DOWN: u8 = 0x80; + +const GAME: &'static str = "/games/gameboy/zelda.gb"; + +static mut GAME_ROM: Option> = None; + +#[repr(C)] +struct Priv {} + +pub fn main() { + print!("Starting Gameboy app"); + + let size = file_len(GAME); + unsafe { GAME_ROM = Some(vec![0_u8; size]) }; + let read = read_file(GAME, 0, unsafe { GAME_ROM.as_mut().unwrap() }); + assert!(size == read); + print!("Rom size: {}", read); + + let mut priv_ = MaybeUninit::::uninit(); + let mut gb = MaybeUninit::::uninit(); + + let init_status = unsafe { + gb_init( + gb.as_mut_ptr(), + Some(gb_rom_read), + Some(gb_cart_ram_read), + Some(gb_cart_ram_write), + Some(gb_error), + priv_.as_mut_ptr() as *mut c_void, + ) + }; + print!("gb init status: {}", init_status); + + unsafe { gb_init_lcd(gb.as_mut_ptr(), Some(lcd_draw_line)) }; + + loop { + let event = get_key(); + if event.state != KeyState::Idle { + match event.key { + KeyCode::Esc => return, + KeyCode::Tab => unsafe { + (*gb.as_mut_ptr()).direct.__bindgen_anon_1.joypad &= !PEANUT_START; + }, + KeyCode::Del => unsafe { + (*gb.as_mut_ptr()).direct.__bindgen_anon_1.joypad &= !PEANUT_SELECT; + }, + KeyCode::Enter => unsafe { + (*gb.as_mut_ptr()).direct.__bindgen_anon_1.joypad &= !PEANUT_A; + }, + KeyCode::Backspace => unsafe { + (*gb.as_mut_ptr()).direct.__bindgen_anon_1.joypad &= !PEANUT_B; + }, + KeyCode::JoyUp => unsafe { + (*gb.as_mut_ptr()).direct.__bindgen_anon_1.joypad &= !PEANUT_UP; + }, + KeyCode::JoyDown => unsafe { + (*gb.as_mut_ptr()).direct.__bindgen_anon_1.joypad &= !PEANUT_DOWN; + }, + KeyCode::JoyLeft => unsafe { + (*gb.as_mut_ptr()).direct.__bindgen_anon_1.joypad &= !PEANUT_LEFT; + }, + KeyCode::JoyRight => unsafe { + (*gb.as_mut_ptr()).direct.__bindgen_anon_1.joypad &= !PEANUT_RIGHT; + }, + _ => (), + }; + }; + + unsafe { gb_run_frame(gb.as_mut_ptr()) }; + } +} diff --git a/user-apps/gboy/src/peanut.rs b/user-apps/gboy/src/peanut.rs new file mode 100644 index 0000000..70b63e3 --- /dev/null +++ b/user-apps/gboy/src/peanut.rs @@ -0,0 +1,85 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +use crate::{DISPLAY, GAME_ROM}; + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); + +use abi::{display::Pixel565, fs::read_file}; +use embedded_graphics::{Drawable, pixelcolor::Rgb565, prelude::Point}; + +pub const GBOY_WIDTH: usize = 160; +pub const GBOY_HEIGHT: usize = 144; + +pub unsafe extern "C" fn gb_rom_read(gb: *mut gb_s, addr: u32) -> u8 { + unsafe { GAME_ROM.as_ref().unwrap()[addr as usize] } +} + +pub unsafe extern "C" fn gb_cart_ram_read(gb: *mut gb_s, addr: u32) -> u8 { + 0 +} + +pub unsafe extern "C" fn gb_cart_ram_write(gb: *mut gb_s, addr: u32, val: u8) {} + +pub unsafe extern "C" fn gb_error(gb: *mut gb_s, err: gb_error_e, addr: u16) {} + +const NUM_PALETTES: usize = 3; +const SHADES_PER_PALETTE: usize = 4; + +const PALETTES: [[Rgb565; SHADES_PER_PALETTE]; NUM_PALETTES] = [ + [ + Rgb565::new(8, 24, 32), + Rgb565::new(52, 104, 86), + Rgb565::new(136, 192, 112), + Rgb565::new(224, 248, 208), + ], // BG + [ + Rgb565::new(8, 24, 32), + Rgb565::new(52, 104, 86), + Rgb565::new(136, 192, 112), + Rgb565::new(224, 248, 208), + ], // OBJ0 + [ + Rgb565::new(8, 24, 32), + Rgb565::new(52, 104, 86), + Rgb565::new(136, 192, 112), + Rgb565::new(224, 248, 208), + ], // OBJ1 +]; + +pub unsafe extern "C" fn lcd_draw_line(_gb: *mut gb_s, pixels: *const u8, line: u8) { + if line < GBOY_HEIGHT as u8 { + let pixels = unsafe { core::slice::from_raw_parts(pixels, GBOY_WIDTH) }; + let y = line as u16; + + for (x, &p) in pixels.iter().enumerate() { + let palette_idx = ((p & 0xF0) >> 4) as usize; + let shade_idx = (p & 0x03) as usize; + + let color = PALETTES + .get(palette_idx) + .and_then(|pal| pal.get(shade_idx)) + .copied() + .unwrap_or(Rgb565::new(0, 0, 0)); + + let sx = (x as u16) * 2; + let sy = y * 2; + + draw_color(color, sx, sy); + draw_color(color, sx + 1, sy); + draw_color(color, sx, sy + 1); + draw_color(color, sx + 1, sy + 1); + } + } +} + +fn draw_color(color: Rgb565, x: u16, y: u16) { + let mut pixel = Pixel565::default(); + pixel.0 = Point::new(x.into(), y.into()); + pixel.1 = color; + + unsafe { + pixel.draw(&mut DISPLAY).unwrap(); + } +} diff --git a/user-apps/nes/src/main.rs b/user-apps/nes/src/main.rs deleted file mode 100644 index 5af8337..0000000 --- a/user-apps/nes/src/main.rs +++ /dev/null @@ -1,88 +0,0 @@ -#![no_std] -#![no_main] -#![allow(static_mut_refs)] - -extern crate alloc; -use abi::{ - Rng, - display::{Display, SCREEN_HEIGHT, SCREEN_WIDTH}, - fs::{file_len, read_file}, - get_key, - keyboard::{KeyCode, KeyState}, - print, sleep, -}; -use alloc::{vec, vec::Vec}; -use core::{ffi::c_void, mem::MaybeUninit, panic::PanicInfo}; -use embedded_graphics::{pixelcolor::Rgb565, prelude::RgbColor}; - -mod peanut; -use peanut::gb_run_frame; - -use crate::peanut::{ - gb_cart_ram_read, gb_cart_ram_write, gb_error, gb_init, gb_init_lcd, gb_rom_read, gb_s, - lcd_draw_line, -}; - -static mut DISPLAY: Display = Display; - -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - print!("user panic: {} @ {:?}", info.message(), info.location(),); - loop {} -} - -#[unsafe(no_mangle)] -pub extern "Rust" fn _start() { - main() -} - -const GAME: &'static str = "/games/nes/game.nes"; - -#[repr(C)] -struct Priv { - rom: Vec, -} - -pub fn main() { - print!("Starting Nes app"); - - let size = file_len(GAME); - let mut priv_ = MaybeUninit::::uninit(); - // let read = unsafe { - // let priv_ptr = priv_.as_mut_ptr(); - // (*priv_ptr).rom = Vec::with_capacity(size); - - // read_file(GAME, 0, &mut (*priv_ptr).rom) - // }; - - // print!("read: {}, file size: {}", read, size); - // assert!(read == size); - - let mut gb = MaybeUninit::::uninit(); - - let init_status = unsafe { - gb_init( - gb.as_mut_ptr(), - Some(gb_rom_read), - Some(gb_cart_ram_read), - Some(gb_cart_ram_write), - Some(gb_error), - priv_.as_mut_ptr() as *mut c_void, - ) - }; - print!("gb init status: {}", init_status); - - unsafe { gb_init_lcd(gb.as_mut_ptr(), Some(lcd_draw_line)) }; - - loop { - let event = get_key(); - if event.state != KeyState::Idle { - let key = match event.key { - KeyCode::Esc => return, - _ => (), - }; - }; - - unsafe { gb_run_frame(gb.as_mut_ptr()) }; - } -} diff --git a/user-apps/nes/src/peanut.rs b/user-apps/nes/src/peanut.rs deleted file mode 100644 index f4d684e..0000000 --- a/user-apps/nes/src/peanut.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![allow(non_upper_case_globals)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] - -use crate::DISPLAY; - -include!(concat!(env!("OUT_DIR"), "/bindings.rs")); - -use abi::{display::Pixel565, fs::read_file}; -use embedded_graphics::{Drawable, pixelcolor::Rgb565, prelude::Point}; - -pub const NES_WIDTH: usize = 256; -pub const NES_HEIGHT: usize = 240; - -pub unsafe extern "C" fn gb_rom_read(gb: *mut gb_s, addr: u32) -> u8 { - let mut buf = [0_u8; 1]; - read_file("/games/nes/rom.nes", addr as usize, &mut buf); - buf[0] -} - -pub unsafe extern "C" fn gb_cart_ram_read(gb: *mut gb_s, addr: u32) -> u8 { - 0 -} - -pub unsafe extern "C" fn gb_cart_ram_write(gb: *mut gb_s, addr: u32, val: u8) {} - -pub unsafe extern "C" fn gb_error(gb: *mut gb_s, err: gb_error_e, addr: u16) {} - -pub unsafe extern "C" fn lcd_draw_line(gb: *mut gb_s, pixels: *const u8, line: u8) { - unsafe { - if line < NES_HEIGHT as u8 { - let pixels = core::slice::from_raw_parts(pixels, NES_WIDTH); - let mut x = 0; - for p in pixels { - let mut pixel = Pixel565::default(); - pixel.0 = Point::new(x, line.into()); - pixel.1 = Rgb565::new(*p, 10, 10); - - pixel.draw(&mut DISPLAY).unwrap(); - - x += 1; - } - } - } -}