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