diff --git a/abi/src/lib.rs b/abi/src/lib.rs index 3d0778e..c18e83b 100644 --- a/abi/src/lib.rs +++ b/abi/src/lib.rs @@ -46,7 +46,6 @@ pub fn get_key() -> KeyEvent { pub mod display { use abi_sys::CPixel; - use alloc::{vec, vec::Vec}; use embedded_graphics::{ Pixel, geometry::{Dimensions, Point}, @@ -54,7 +53,6 @@ pub mod display { prelude::{DrawTarget, Size}, primitives::Rectangle, }; - use once_cell::unsync::Lazy; pub const SCREEN_WIDTH: usize = 320; pub const SCREEN_HEIGHT: usize = 320; diff --git a/justfile b/justfile index a8fa389..c883dfc 100644 --- a/justfile +++ b/justfile @@ -17,3 +17,4 @@ userapps: cbindgen just userapp snake just userapp gallery just userapp gif + just userapp doom diff --git a/user-apps/doom/build.rs b/user-apps/doom/build.rs index 6342e96..1dfa714 100644 --- a/user-apps/doom/build.rs +++ b/user-apps/doom/build.rs @@ -11,9 +11,13 @@ use std::env; use std::fs::File; use std::io::Write; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; +use std::process::Command; fn main() { + build_newlib(); + build_doom(); + // Put `memory.x` in our output directory and ensure it's // on the linker search path. let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); @@ -25,7 +29,58 @@ fn main() { println!("cargo:rerun-if-changed=memory.x"); println!("cargo:rustc-link-arg-bins=-Tmemory.x"); +} +// TODO: use target to change newlib build - only workds for rp2350 right now +fn build_newlib() { + let out_dir = std::env::var("OUT_DIR").unwrap(); + let picolibc_dir = format!("{}/picolibc", out_dir); + + if !Path::new(&picolibc_dir).exists() { + let status = Command::new("git") + .args(&[ + "clone", + "https://github.com/picolibc/picolibc", + &picolibc_dir, + ]) + .status() + .expect("Failed to clone picolibc"); + assert!(status.success()); + } + + let build_dir = format!("{}/build", picolibc_dir); + std::fs::create_dir_all(&build_dir).unwrap(); + + let status = Command::new(&format!("{picolibc_dir}/scripts/do-configure")) + .current_dir(&build_dir) + .args(&[ + "thumbv8m_main_fp-none-eabi", + "--buildtype=minsize", + "-Dtests=true", + "-Dtinystdio=false", + "-Dsingle-thread=true", + "-Db_pie=true", + "-Ddefault_library=static", + "-Dtinystdio=false", + "-Dmultilib=false", + ".", + ]) + .status() + .expect("Failed to run Meson configure"); + assert!(status.success()); + + let status = Command::new("ninja") + .current_dir(&build_dir) + .status() + .expect("Failed to run Ninja build"); + assert!(status.success()); + + println!("cargo:rustc-link-search={}/newlib", build_dir); + println!("cargo:rustc-link-lib=c"); + println!("cargo:rustc-link-lib=m"); +} + +fn build_doom() { let ref dg_src_dir = std::path::PathBuf::from("doomgeneric/doomgeneric"); let mut dg_c_paths = vec![]; let mut dg_h_paths = vec![]; @@ -37,6 +92,7 @@ fn main() { if filename.starts_with("doomgeneric") || filename.contains("_allegro") || filename.contains("_sdl") + || filename.contains("net_") || filename == "i_main.c" { continue; @@ -55,16 +111,16 @@ fn main() { .for_each(|path| println!("cargo:rerun-if-changed={}", path.to_str().unwrap())); cc::Build::new() + .compiler("arm-none-eabi-gcc") .flag("-w") // silence warnings .flag("-Os") // optimize for size + .flag("-ffunction-sections") + .flag("-fdata-sections") .define("CMAP256", None) .define("DOOMGENERIC_RESX", Some("320")) .define("DOOMGENERIC_RESY", Some("200")) - .define("MAXPLAYERS", Some("1")) - .flag_if_supported("-std=gnu89") // old-style C, allows implicit int - .flag("-Wno-implicit-function-declaration") // ignore missing prototypes + .flag_if_supported("-std=gnu99") .define("_POSIX_C_SOURCE", Some("200809L")) .files(dg_c_paths) - .include(".") .compile("doomgeneric"); } diff --git a/user-apps/doom/inttypes.h b/user-apps/doom/inttypes.h deleted file mode 100644 index d2edacc..0000000 --- a/user-apps/doom/inttypes.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef INTTYPES_H -#define INTTYPES_H - -#endif diff --git a/user-apps/doom/limits.h b/user-apps/doom/limits.h deleted file mode 100644 index 9ef223e..0000000 --- a/user-apps/doom/limits.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef STRINGS_H -#define STRINGS_H - -#endif diff --git a/user-apps/doom/src/doom.rs b/user-apps/doom/src/doom.rs index 13cc7f6..416dd6b 100644 --- a/user-apps/doom/src/doom.rs +++ b/user-apps/doom/src/doom.rs @@ -1,10 +1,72 @@ +use abi::{ + abi_sys::{get_ms, sleep}, + display::Display, +}; +use core::ffi::{c_int, c_uchar}; +use embedded_graphics::{ + Drawable, Pixel, + draw_target::DrawTarget, + pixelcolor::Rgb565, + prelude::{Point, RgbColor}, +}; + +#[unsafe(no_mangle)] +#[allow(non_snake_case)] +static mut DG_ScreenBuffer: *const u8 = core::ptr::null(); + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct RGBA { + pub b: u8, + pub g: u8, + pub r: u8, + pub a: u8, +} + +unsafe extern "C" { + fn D_DoomMain(); + fn doomgeneric_Tick(); + fn M_FindResponseFile(); + + pub static colors: [RGBA; 256]; +} + +pub fn tick() { + unsafe { doomgeneric_Tick() }; +} + +pub struct ScreenBuffer(pub [u8; SIZE]); + +impl ScreenBuffer { + #[allow(dead_code)] + const NA: () = assert!(SIZE == RESX * RESY); + + pub const fn new() -> Self { + Self([0_u8; SIZE]) + } +} + +#[unsafe(no_mangle)] +extern "C" fn DG_SetWindowTitle() {} + +pub fn create( + screenbuffer: &ScreenBuffer, +) { + unsafe { + M_FindResponseFile(); + + DG_ScreenBuffer = screenbuffer.0.as_ptr(); + + D_DoomMain(); + } +} + const X: usize = 320; const Y: usize = 200; const SIZE: usize = X * Y; -pub static mut DISPLAY: Option> = None; +pub static mut DISPLAY: Option = None; pub static mut SCREEN_BUFFER: ScreenBuffer = ScreenBuffer::new(); -pub static mut START: Option = None; #[unsafe(no_mangle)] extern "C" fn DG_DrawFrame() { @@ -36,20 +98,15 @@ extern "C" fn DG_DrawFrame() { #[unsafe(no_mangle)] extern "C" fn DG_GetTicksMs() -> u32 { - let start = unsafe { START.unwrap() }; - Instant::now() - .duration_since(start) - .as_millis() - .try_into() - .expect("Cannot Fit Start time into u32") + get_ms() as u32 } #[unsafe(no_mangle)] -extern "C" fn DG_GetKey(pressed: *mut raw::c_int, key: *mut raw::c_uchar) -> raw::c_int { +extern "C" fn DG_GetKey(pressed: *mut c_int, key: *mut c_uchar) -> c_int { 0 } #[unsafe(no_mangle)] extern "C" fn DG_SleepMs(ms: u32) { - sleep(Duration::from_millis(ms as u64)); + sleep(ms.into()); } diff --git a/user-apps/doom/src/libc.rs b/user-apps/doom/src/libc.rs new file mode 100644 index 0000000..496fef9 --- /dev/null +++ b/user-apps/doom/src/libc.rs @@ -0,0 +1,118 @@ +use core::ffi::{c_char, c_int, c_uchar, c_void}; +use core::ptr; + +#[unsafe(no_mangle)] +pub static _ctype_: [c_uchar; 256] = [0u8; 256]; + +#[repr(C)] +pub struct Reent { + pub errno: c_int, + _reserved: [u8; 32], +} + +#[unsafe(no_mangle)] +pub static mut _reent_data: Reent = Reent { + errno: 0, + _reserved: [0; 32], +}; + +#[unsafe(no_mangle)] +pub static mut _impure_ptr: *mut Reent = unsafe { &mut _reent_data as *mut Reent }; + +#[unsafe(no_mangle)] +pub extern "C" fn __errno() -> *mut c_int { + unsafe { &mut (*_impure_ptr).errno as *mut c_int } +} + +#[unsafe(no_mangle)] +pub extern "C" fn exit(_status: i32) -> ! { + loop {} +} + +#[unsafe(no_mangle)] +pub extern "C" fn close(_file: i32) -> i32 { + -1 +} + +#[repr(C)] +pub struct Stat { + st_mode: u32, +} + +#[unsafe(no_mangle)] +pub extern "C" fn fstat(_file: i32, st: *mut Stat) -> i32 { + unsafe { + if !st.is_null() { + (*st).st_mode = 0x2000; // S_IFCHR + } + } + 0 +} + +#[unsafe(no_mangle)] +pub extern "C" fn isatty(_file: i32) -> i32 { + 1 +} + +#[unsafe(no_mangle)] +pub extern "C" fn lseek(_file: i32, _ptr: i32, _dir: i32) -> i32 { + 0 +} + +#[unsafe(no_mangle)] +pub extern "C" fn lseek64(_fd: c_int, _offset: i64, _whence: c_int) -> i64 { + 0 +} + +#[unsafe(no_mangle)] +pub extern "C" fn open(_name: *const u8, _flags: i32, _mode: i32) -> i32 { + -1 +} + +#[unsafe(no_mangle)] +pub extern "C" fn read(_file: i32, _ptr: *mut u8, len: usize) -> i32 { + len as i32 +} + +#[unsafe(no_mangle)] +pub extern "C" fn write(_file: i32, _ptr: *const u8, len: usize) -> i32 { + len as i32 +} + +#[unsafe(no_mangle)] +pub extern "C" fn rename(_old: *const c_char, _new: *const c_char) -> c_int { + -1 +} + +#[unsafe(no_mangle)] +pub extern "C" fn kill(_pid: i32, _sig: i32) -> i32 { + -1 +} + +#[unsafe(no_mangle)] +pub extern "C" fn getpid() -> i32 { + 1 +} + +#[unsafe(no_mangle)] +pub extern "C" fn link(_old: *const u8, _new: *const u8) -> i32 { + -1 +} + +#[unsafe(no_mangle)] +pub extern "C" fn unlink(_name: *const u8) -> i32 { + -1 +} + +#[unsafe(no_mangle)] +pub extern "C" fn mkdir(_path: *const u8, _mode: u32) -> i32 { + 0 +} + +#[unsafe(no_mangle)] +pub extern "C" fn sbrk(incr: isize) -> *mut c_void { + core::ptr::null_mut() +} + +#[unsafe(no_mangle)] +pub extern "C" fn fini() {} diff --git a/user-apps/doom/src/main.rs b/user-apps/doom/src/main.rs index 613849c..99dd11a 100644 --- a/user-apps/doom/src/main.rs +++ b/user-apps/doom/src/main.rs @@ -1,5 +1,7 @@ #![no_std] #![no_main] +#![allow(static_mut_refs)] +#![feature(c_variadic)] extern crate alloc; use abi::{ @@ -13,6 +15,10 @@ use alloc::vec; use core::panic::PanicInfo; use embedded_graphics::{pixelcolor::Rgb565, prelude::Point}; +mod doom; +use crate::doom::{DISPLAY, SCREEN_BUFFER, create, tick}; +mod libc; + #[panic_handler] fn panic(info: &PanicInfo) -> ! { print!("user panic: {} @ {:?}", info.message(), info.location(),); @@ -26,5 +32,12 @@ pub extern "Rust" fn _start() { pub fn main() { print!("Starting Doom app"); - let mut display = Display; + let display = Display; + unsafe { DISPLAY = Some(display) }; + + unsafe { create(&SCREEN_BUFFER) }; + + loop { + tick(); + } } diff --git a/user-apps/doom/stdio.h b/user-apps/doom/stdio.h deleted file mode 100644 index b86ad68..0000000 --- a/user-apps/doom/stdio.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef STDIO_H -#define STDIO_H - -#endif diff --git a/user-apps/doom/string.h b/user-apps/doom/string.h deleted file mode 100644 index e8f8650..0000000 --- a/user-apps/doom/string.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef STRING_H -#define STRING_H - -#endif diff --git a/user-apps/doom/strings.h b/user-apps/doom/strings.h deleted file mode 100644 index 9ef223e..0000000 --- a/user-apps/doom/strings.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef STRINGS_H -#define STRINGS_H - -#endif