1#![no_std]
2mod heap;
9
10extern crate alloc;
11
12use tg_console::log;
13
14pub use tg_console::{print, println};
15pub use tg_syscall::*;
16
17#[cfg(feature = "tangram")]
18pub mod tangram;
19
20#[cfg(feature = "snake")]
21pub mod snake;
22
23#[cfg(feature = "tetris")]
24pub mod tetris;
25
26#[cfg(feature = "pingpong")]
27pub mod pingpong;
28
29#[cfg(feature = "breakout")]
30pub mod breakout;
31
32#[cfg(feature = "pacman")]
33pub mod pacman;
34
35#[cfg(feature = "doom")]
36pub mod doom;
37
38pub fn fb_info() -> (u32, u32) {
41 let packed: usize;
42 unsafe {
43 core::arch::asm!(
44 "ecall",
45 in("a7") 2000usize,
46 lateout("a0") packed,
47 );
48 }
49 let width = (packed >> 32) as u32;
50 let height = packed as u32;
51 (width, height)
52}
53
54pub fn fb_write(x: u32, y: u32, w: u32, h: u32, data: *const u8) -> isize {
57 let ret: isize;
58 unsafe {
59 core::arch::asm!(
60 "ecall",
61 in("a7") 2001usize,
62 inlateout("a0") x as usize => ret,
63 in("a1") y as usize,
64 in("a2") w as usize,
65 in("a3") h as usize,
66 in("a4") data as usize,
67 );
68 }
69 ret
70}
71
72pub fn shm_create() -> usize {
75 let ret: usize;
76 unsafe {
77 core::arch::asm!(
78 "ecall",
79 in("a7") 2002usize,
80 lateout("a0") ret,
81 );
82 }
83 ret
84}
85
86pub fn fb_flush() {
89 unsafe {
90 core::arch::asm!(
91 "ecall",
92 in("a7") 2003usize,
93 lateout("a0") _,
94 );
95 }
96}
97#[unsafe(no_mangle)]
98#[unsafe(link_section = ".text.entry")]
99pub extern "C" fn _start() -> ! {
100 tg_console::init_console(&Console);
102 tg_console::set_log_level(option_env!("LOG"));
103 heap::init();
104
105 unsafe extern "C" {
106 fn main() -> i32;
107 }
108
109 exit(unsafe { main() });
111 unreachable!()
112}
113
114#[panic_handler]
115fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! {
116 let err = panic_info.message();
117 if let Some(location) = panic_info.location() {
118 log::error!("Panicked at {}:{}, {err}", location.file(), location.line());
119 } else {
120 log::error!("Panicked: {err}");
121 }
122 exit(1);
123 unreachable!()
124}
125
126pub const STDIN_BUFFERED: usize = 3;
128
129pub fn getchar() -> u8 {
130 let mut c = [0u8; 1];
131 loop {
132 let n = read(STDIN, &mut c);
133 if n > 0 && c[0] != 0 {
134 return c[0];
135 }
136 sched_yield();
137 }
138}
139
140struct Console;
141
142impl tg_console::Console for Console {
143 #[inline]
144 fn put_char(&self, c: u8) {
145 tg_syscall::write(STDOUT, &[c]);
146 }
147
148 #[inline]
149 fn put_str(&self, s: &str) {
150 tg_syscall::write(STDOUT, s.as_bytes());
151 }
152}
153
154pub fn sleep(period_ms: usize) {
155 let mut time: TimeSpec = TimeSpec::ZERO;
157 clock_gettime(ClockId::CLOCK_MONOTONIC, &mut time as *mut _ as _);
158 let time = time + TimeSpec::from_millsecond(period_ms);
159 loop {
160 let mut now: TimeSpec = TimeSpec::ZERO;
161 clock_gettime(ClockId::CLOCK_MONOTONIC, &mut now as *mut _ as _);
162 if now > time {
163 break;
164 }
165 sched_yield();
166 }
167}
168
169pub fn get_time() -> isize {
170 let mut time: TimeSpec = TimeSpec::ZERO;
171 clock_gettime(ClockId::CLOCK_MONOTONIC, &mut time as *mut _ as _);
172 (time.tv_sec * 1000 + time.tv_nsec / 1_000_000) as isize
173}
174
175pub fn trace_read(ptr: *const u8) -> Option<u8> {
176 let ret = trace(0, ptr as usize, 0);
177 if ret >= 0 && ret <= 255 {
178 Some(ret as u8)
179 } else {
180 None
181 }
182}
183
184pub fn trace_write(ptr: *const u8, value: u8) -> isize {
185 trace(1, ptr as usize, value as usize)
186}
187
188pub fn count_syscall(syscall_id: usize) -> isize {
189 trace(2, syscall_id, 0)
190}
191
192pub fn pipe_read(pipe_fd: usize, buffer: &mut [u8]) -> isize {
195 let mut total_read = 0usize;
196 let len = buffer.len();
197 loop {
198 if total_read >= len {
199 return total_read as isize;
200 }
201 let ret = read(pipe_fd, &mut buffer[total_read..]);
202 if ret == -2 {
203 sched_yield();
205 continue;
206 } else if ret == 0 {
207 return total_read as isize;
209 } else if ret < 0 {
210 return ret;
212 } else {
213 total_read += ret as usize;
214 }
215 }
216}
217
218pub fn pipe_write(pipe_fd: usize, buffer: &[u8]) -> isize {
221 let mut total_write = 0usize;
222 let len = buffer.len();
223 loop {
224 if total_write >= len {
225 return total_write as isize;
226 }
227 let ret = write(pipe_fd, &buffer[total_write..]);
228 if ret == -2 {
229 sched_yield();
231 continue;
232 } else if ret < 0 {
233 return ret;
235 } else {
236 total_write += ret as usize;
237 }
238 }
239}