#![no_std]
mod heap;
extern crate alloc;
use tg_console::log;
pub use tg_console::{print, println};
pub use tg_syscall::*;
#[cfg(feature = "tangram")]
pub mod tangram;
#[cfg(feature = "snake")]
pub mod snake;
#[cfg(feature = "tetris")]
pub mod tetris;
#[cfg(feature = "pingpong")]
pub mod pingpong;
#[cfg(feature = "breakout")]
pub mod breakout;
#[cfg(feature = "pacman")]
pub mod pacman;
#[cfg(feature = "doom")]
pub mod doom;
pub fn fb_info() -> (u32, u32) {
let packed: usize;
unsafe {
core::arch::asm!(
"ecall",
in("a7") 2000usize,
lateout("a0") packed,
);
}
let width = (packed >> 32) as u32;
let height = packed as u32;
(width, height)
}
pub fn fb_write(x: u32, y: u32, w: u32, h: u32, data: *const u8) -> isize {
let ret: isize;
unsafe {
core::arch::asm!(
"ecall",
in("a7") 2001usize,
inlateout("a0") x as usize => ret,
in("a1") y as usize,
in("a2") w as usize,
in("a3") h as usize,
in("a4") data as usize,
);
}
ret
}
pub fn shm_create() -> usize {
let ret: usize;
unsafe {
core::arch::asm!(
"ecall",
in("a7") 2002usize,
lateout("a0") ret,
);
}
ret
}
pub fn fb_flush() {
unsafe {
core::arch::asm!(
"ecall",
in("a7") 2003usize,
lateout("a0") _,
);
}
}
#[unsafe(no_mangle)]
#[unsafe(link_section = ".text.entry")]
pub extern "C" fn _start() -> ! {
tg_console::init_console(&Console);
tg_console::set_log_level(option_env!("LOG"));
heap::init();
unsafe extern "C" {
fn main() -> i32;
}
exit(unsafe { main() });
unreachable!()
}
#[panic_handler]
fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! {
let err = panic_info.message();
if let Some(location) = panic_info.location() {
log::error!("Panicked at {}:{}, {err}", location.file(), location.line());
} else {
log::error!("Panicked: {err}");
}
exit(1);
unreachable!()
}
pub const STDIN_BUFFERED: usize = 3;
pub fn getchar() -> u8 {
let mut c = [0u8; 1];
loop {
let n = read(STDIN, &mut c);
if n > 0 && c[0] != 0 {
return c[0];
}
sched_yield();
}
}
struct Console;
impl tg_console::Console for Console {
#[inline]
fn put_char(&self, c: u8) {
tg_syscall::write(STDOUT, &[c]);
}
#[inline]
fn put_str(&self, s: &str) {
tg_syscall::write(STDOUT, s.as_bytes());
}
}
pub fn sleep(period_ms: usize) {
let mut time: TimeSpec = TimeSpec::ZERO;
clock_gettime(ClockId::CLOCK_MONOTONIC, &mut time as *mut _ as _);
let time = time + TimeSpec::from_millsecond(period_ms);
loop {
let mut now: TimeSpec = TimeSpec::ZERO;
clock_gettime(ClockId::CLOCK_MONOTONIC, &mut now as *mut _ as _);
if now > time {
break;
}
sched_yield();
}
}
pub fn get_time() -> isize {
let mut time: TimeSpec = TimeSpec::ZERO;
clock_gettime(ClockId::CLOCK_MONOTONIC, &mut time as *mut _ as _);
(time.tv_sec * 1000 + time.tv_nsec / 1_000_000) as isize
}
pub fn trace_read(ptr: *const u8) -> Option<u8> {
let ret = trace(0, ptr as usize, 0);
if ret >= 0 && ret <= 255 {
Some(ret as u8)
} else {
None
}
}
pub fn trace_write(ptr: *const u8, value: u8) -> isize {
trace(1, ptr as usize, value as usize)
}
pub fn count_syscall(syscall_id: usize) -> isize {
trace(2, syscall_id, 0)
}
pub fn pipe_read(pipe_fd: usize, buffer: &mut [u8]) -> isize {
let mut total_read = 0usize;
let len = buffer.len();
loop {
if total_read >= len {
return total_read as isize;
}
let ret = read(pipe_fd, &mut buffer[total_read..]);
if ret == -2 {
sched_yield();
continue;
} else if ret == 0 {
return total_read as isize;
} else if ret < 0 {
return ret;
} else {
total_read += ret as usize;
}
}
}
pub fn pipe_write(pipe_fd: usize, buffer: &[u8]) -> isize {
let mut total_write = 0usize;
let len = buffer.len();
loop {
if total_write >= len {
return total_write as isize;
}
let ret = write(pipe_fd, &buffer[total_write..]);
if ret == -2 {
sched_yield();
continue;
} else if ret < 0 {
return ret;
} else {
total_write += ret as usize;
}
}
}