feat(userspace-rt): add runtime crate with entry point, panic handler, and allocator re-export
Snake and hello apps now use extern crate userspace_rt — no more boilerplate assembly or panic handlers in app code.
This commit is contained in:
@@ -1,48 +1,31 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
extern crate userspace_rt;
|
||||
|
||||
use snake::game::{Direction, GameState, Snake};
|
||||
use snake::renderer::{render, RenderCommand};
|
||||
use userspace_rt::syscall;
|
||||
|
||||
const DISPLAY_EP: usize = 0;
|
||||
const INPUT_EP: usize = 1;
|
||||
const TICK_DELAY: usize = 2_000_000;
|
||||
const MAX_RENDER_COMMANDS: usize = 192;
|
||||
|
||||
#[cfg(not(test))]
|
||||
use core::arch::global_asm;
|
||||
|
||||
#[cfg(not(test))]
|
||||
global_asm!(
|
||||
r#"
|
||||
.section .text.entry
|
||||
.globl _start
|
||||
_start:
|
||||
call main
|
||||
j _start
|
||||
"#
|
||||
);
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[unsafe(no_mangle)]
|
||||
extern "C" fn main() -> ! {
|
||||
run_game();
|
||||
}
|
||||
|
||||
fn run_game() -> ! {
|
||||
extern "C" fn main() {
|
||||
let mut snake = Snake::new();
|
||||
let mut commands = [RenderCommand { x: 0, y: 0, w: 0, h: 0, color: 0 }; MAX_RENDER_COMMANDS];
|
||||
|
||||
loop {
|
||||
handle_input(&mut snake);
|
||||
|
||||
snake.tick();
|
||||
|
||||
let count = render(&snake, &mut commands);
|
||||
send_render_commands(&commands, count);
|
||||
|
||||
if snake.state() == GameState::GameOver {
|
||||
userspace::syscall::exit();
|
||||
return;
|
||||
}
|
||||
|
||||
wait_tick();
|
||||
@@ -50,11 +33,9 @@ fn run_game() -> ! {
|
||||
}
|
||||
|
||||
fn handle_input(snake: &mut Snake) {
|
||||
// PollEvent request: tag=0
|
||||
let _ = userspace::syscall::send(INPUT_EP, 0, 0, 0, 0);
|
||||
let (tag, kind, _data, _) = userspace::syscall::receive(INPUT_EP);
|
||||
let _ = syscall::send(INPUT_EP, 0, 0, 0, 0);
|
||||
let (tag, kind, _, _) = syscall::receive(INPUT_EP);
|
||||
|
||||
// InputResponse::Event(KeyDown(key)): tag=1, key_kind in word 1
|
||||
if tag == 1 {
|
||||
match kind {
|
||||
0 => snake.set_direction(Direction::Up),
|
||||
@@ -67,34 +48,25 @@ fn handle_input(snake: &mut Snake) {
|
||||
}
|
||||
|
||||
fn send_render_commands(commands: &[RenderCommand], count: usize) {
|
||||
// Clear: DisplayRequest tag=1
|
||||
let _ = userspace::syscall::send(DISPLAY_EP, 1, 0, 0, 0);
|
||||
let _ = userspace::syscall::receive(DISPLAY_EP);
|
||||
let _ = syscall::send(DISPLAY_EP, 1, 0, 0, 0);
|
||||
let _ = syscall::receive(DISPLAY_EP);
|
||||
|
||||
for i in 0..count {
|
||||
let cmd = &commands[i];
|
||||
// DrawRect: DisplayRequest tag=0, xy packed, wh packed, color
|
||||
let xy = cmd.x as usize | ((cmd.y as usize) << 16);
|
||||
let wh = cmd.w as usize | ((cmd.h as usize) << 16);
|
||||
let _ = userspace::syscall::send(DISPLAY_EP, 0, xy, wh, cmd.color as usize);
|
||||
let _ = userspace::syscall::receive(DISPLAY_EP);
|
||||
let _ = syscall::send(DISPLAY_EP, 0, xy, wh, cmd.color as usize);
|
||||
let _ = syscall::receive(DISPLAY_EP);
|
||||
}
|
||||
|
||||
// Flush: DisplayRequest tag=2
|
||||
let _ = userspace::syscall::send(DISPLAY_EP, 2, 0, 0, 0);
|
||||
let _ = userspace::syscall::receive(DISPLAY_EP);
|
||||
let _ = syscall::send(DISPLAY_EP, 2, 0, 0, 0);
|
||||
let _ = syscall::receive(DISPLAY_EP);
|
||||
}
|
||||
|
||||
fn wait_tick() {
|
||||
let start = userspace::syscall::get_time();
|
||||
let start = syscall::get_time();
|
||||
let deadline = start + TICK_DELAY;
|
||||
while userspace::syscall::get_time() < deadline {
|
||||
userspace::syscall::yield_now();
|
||||
while syscall::get_time() < deadline {
|
||||
syscall::yield_now();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[panic_handler]
|
||||
fn panic(_: &core::panic::PanicInfo) -> ! {
|
||||
userspace::syscall::exit();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user