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