mirror of
https://github.com/LegitCamper/picocalc-os-rs.git
synced 2025-12-28 00:05:28 +00:00
init
This commit is contained in:
12
user-apps/nes/Cargo.toml
Normal file
12
user-apps/nes/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "nes"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = "0.71.0"
|
||||
cc = "1.2.44"
|
||||
|
||||
[dependencies]
|
||||
abi = { path = "../../abi" }
|
||||
embedded-graphics = "0.8.1"
|
||||
1
user-apps/nes/Peanut-GB
Submodule
1
user-apps/nes/Peanut-GB
Submodule
Submodule user-apps/nes/Peanut-GB added at a52866507f
54
user-apps/nes/build.rs
Normal file
54
user-apps/nes/build.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
//! This build script copies the `memory.x` file from the crate root into
|
||||
//! a directory where the linker can always find it at build time.
|
||||
//! For many projects this is optional, as the linker always searches the
|
||||
//! project root directory -- wherever `Cargo.toml` is. However, if you
|
||||
//! are using a workspace or have a more complicated build setup, this
|
||||
//! build script becomes required. Additionally, by requesting that
|
||||
//! Cargo re-run the build script whenever `memory.x` is changed,
|
||||
//! updating `memory.x` ensures a rebuild of the application with the
|
||||
//! new memory settings.
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
bindgen();
|
||||
|
||||
// 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());
|
||||
File::create(out.join("memory.x"))
|
||||
.unwrap()
|
||||
.write_all(include_bytes!("../memory.x"))
|
||||
.unwrap();
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
|
||||
println!("cargo:rerun-if-changed=memory.x");
|
||||
println!("cargo:rustc-link-arg-bins=-Tmemory.x");
|
||||
}
|
||||
|
||||
fn bindgen() {
|
||||
let bindings = bindgen::Builder::default()
|
||||
.header("Peanut-GB/peanut_gb.h")
|
||||
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
|
||||
.clang_arg("-I../../picolibc/newlib/libc/include/")
|
||||
.clang_arg("-I../../picolibc/build/")
|
||||
.use_core()
|
||||
.generate()
|
||||
.expect("Unable to generate bindings");
|
||||
|
||||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
bindings
|
||||
.write_to_file(out_path.join("bindings.rs"))
|
||||
.expect("Couldn't write bindings!");
|
||||
|
||||
cc::Build::new()
|
||||
.file("peanut_gb_stub.c")
|
||||
.include("Peanut-GB")
|
||||
.compile("peanut_gb");
|
||||
|
||||
println!("cargo:rustc-link-search=Peanut-GB");
|
||||
println!("cargo:rustc-link-lib=peanut_gb");
|
||||
}
|
||||
1
user-apps/nes/peanut_gb_stub.c
Normal file
1
user-apps/nes/peanut_gb_stub.c
Normal file
@@ -0,0 +1 @@
|
||||
#include <peanut_gb.h>
|
||||
88
user-apps/nes/src/main.rs
Normal file
88
user-apps/nes/src/main.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
#![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<u8>,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
print!("Starting Nes app");
|
||||
|
||||
let size = file_len(GAME);
|
||||
let mut priv_ = MaybeUninit::<Priv>::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::<gb_s>::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()) };
|
||||
}
|
||||
}
|
||||
45
user-apps/nes/src/peanut.rs
Normal file
45
user-apps/nes/src/peanut.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
#![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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user