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
32pub fn fb_info() -> (u32, u32) {
35 let packed: usize;
36 unsafe {
37 core::arch::asm!(
38 "ecall",
39 in("a7") 2000usize,
40 lateout("a0") packed,
41 );
42 }
43 let width = (packed >> 32) as u32;
44 let height = packed as u32;
45 (width, height)
46}
47
48pub fn fb_write(x: u32, y: u32, w: u32, h: u32, data: *const u8) -> isize {
51 let ret: isize;
52 unsafe {
53 core::arch::asm!(
54 "ecall",
55 in("a7") 2001usize,
56 inlateout("a0") x as usize => ret,
57 in("a1") y as usize,
58 in("a2") w as usize,
59 in("a3") h as usize,
60 in("a4") data as usize,
61 );
62 }
63 ret
64}
65
66pub fn shm_create() -> usize {
69 let ret: usize;
70 unsafe {
71 core::arch::asm!(
72 "ecall",
73 in("a7") 2002usize,
74 lateout("a0") ret,
75 );
76 }
77 ret
78}
79
80pub fn fb_flush() {
83 unsafe {
84 core::arch::asm!(
85 "ecall",
86 in("a7") 2003usize,
87 lateout("a0") _,
88 );
89 }
90}
91#[unsafe(no_mangle)]
92#[unsafe(link_section = ".text.entry")]
93pub extern "C" fn _start() -> ! {
94 tg_console::init_console(&Console);
96 tg_console::set_log_level(option_env!("LOG"));
97 heap::init();
98
99 unsafe extern "C" {
100 fn main() -> i32;
101 }
102
103 exit(unsafe { main() });
105 unreachable!()
106}
107
108#[panic_handler]
109fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! {
110 let err = panic_info.message();
111 if let Some(location) = panic_info.location() {
112 log::error!("Panicked at {}:{}, {err}", location.file(), location.line());
113 } else {
114 log::error!("Panicked: {err}");
115 }
116 exit(1);
117 unreachable!()
118}
119
120pub const STDIN_BUFFERED: usize = 3;
122
123pub fn getchar() -> u8 {
124 let mut c = [0u8; 1];
125 loop {
126 let n = read(STDIN, &mut c);
127 if n > 0 && c[0] != 0 {
128 return c[0];
129 }
130 sched_yield();
131 }
132}
133
134struct Console;
135
136impl tg_console::Console for Console {
137 #[inline]
138 fn put_char(&self, c: u8) {
139 tg_syscall::write(STDOUT, &[c]);
140 }
141
142 #[inline]
143 fn put_str(&self, s: &str) {
144 tg_syscall::write(STDOUT, s.as_bytes());
145 }
146}
147
148pub fn sleep(period_ms: usize) {
149 let mut time: TimeSpec = TimeSpec::ZERO;
151 clock_gettime(ClockId::CLOCK_MONOTONIC, &mut time as *mut _ as _);
152 let time = time + TimeSpec::from_millsecond(period_ms);
153 loop {
154 let mut now: TimeSpec = TimeSpec::ZERO;
155 clock_gettime(ClockId::CLOCK_MONOTONIC, &mut now as *mut _ as _);
156 if now > time {
157 break;
158 }
159 sched_yield();
160 }
161}
162
163pub fn get_time() -> isize {
164 let mut time: TimeSpec = TimeSpec::ZERO;
165 clock_gettime(ClockId::CLOCK_MONOTONIC, &mut time as *mut _ as _);
166 (time.tv_sec * 1000 + time.tv_nsec / 1_000_000) as isize
167}
168
169pub fn trace_read(ptr: *const u8) -> Option<u8> {
170 let ret = trace(0, ptr as usize, 0);
171 if ret >= 0 && ret <= 255 {
172 Some(ret as u8)
173 } else {
174 None
175 }
176}
177
178pub fn trace_write(ptr: *const u8, value: u8) -> isize {
179 trace(1, ptr as usize, value as usize)
180}
181
182pub fn count_syscall(syscall_id: usize) -> isize {
183 trace(2, syscall_id, 0)
184}
185
186pub fn pipe_read(pipe_fd: usize, buffer: &mut [u8]) -> isize {
189 let mut total_read = 0usize;
190 let len = buffer.len();
191 loop {
192 if total_read >= len {
193 return total_read as isize;
194 }
195 let ret = read(pipe_fd, &mut buffer[total_read..]);
196 if ret == -2 {
197 sched_yield();
199 continue;
200 } else if ret == 0 {
201 return total_read as isize;
203 } else if ret < 0 {
204 return ret;
206 } else {
207 total_read += ret as usize;
208 }
209 }
210}
211
212pub fn pipe_write(pipe_fd: usize, buffer: &[u8]) -> isize {
215 let mut total_write = 0usize;
216 let len = buffer.len();
217 loop {
218 if total_write >= len {
219 return total_write as isize;
220 }
221 let ret = write(pipe_fd, &buffer[total_write..]);
222 if ret == -2 {
223 sched_yield();
225 continue;
226 } else if ret < 0 {
227 return ret;
229 } else {
230 total_write += ret as usize;
231 }
232 }
233}