6 #include <machine/syscall.h>
10 #define static_assert(cond) switch(0) { case 0: case !!(long)(cond): ; }
12 static long handle_frontend_syscall(long which
, long arg0
, long arg1
, long arg2
)
14 volatile uint64_t magic_mem
[8] __attribute__((aligned(64)));
20 write_csr(tohost
, (long)magic_mem
);
21 while (swap_csr(fromhost
, 0) == 0);
25 // In setStats, we might trap reading uarch-specific counters.
26 // The trap handler will skip over the instruction and write 0,
27 // but only if v0 is the destination register.
28 #define read_csr_safe(reg) ({ register long __tmp asm("v0"); \
29 asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
32 #define NUM_COUNTERS 18
33 static long counters
[NUM_COUNTERS
];
34 static char* counter_names
[NUM_COUNTERS
];
35 static int handle_stats(int enable
)
37 //use csrs to set stats register
45 #define READ_CTR(name) do { \
46 while (i >= NUM_COUNTERS) ; \
47 long csr = read_csr_safe(name); \
48 if (!enable) { csr -= counters[i]; counter_names[i] = #name; } \
49 counters[i++] = csr; \
51 READ_CTR(cycle
); READ_CTR(instret
);
52 READ_CTR(uarch0
); READ_CTR(uarch1
); READ_CTR(uarch2
); READ_CTR(uarch3
);
53 READ_CTR(uarch4
); READ_CTR(uarch5
); READ_CTR(uarch6
); READ_CTR(uarch7
);
54 READ_CTR(uarch8
); READ_CTR(uarch9
); READ_CTR(uarch10
); READ_CTR(uarch11
);
55 READ_CTR(uarch12
); READ_CTR(uarch13
); READ_CTR(uarch14
); READ_CTR(uarch15
);
66 static void tohost_exit(int code
)
68 write_csr(tohost
, (code
<< 1) | 1);
72 long handle_trap(long cause
, long epc
, long regs
[32])
75 asm volatile ("lw %0, 1f; j 2f; 1: csrr v0, stats; 2:" : "=r"(csr_insn
));
78 if (cause
== CAUSE_ILLEGAL_INSTRUCTION
&&
79 (*(int*)epc
& csr_insn
) == csr_insn
)
81 else if (cause
!= CAUSE_SYSCALL
)
83 else if (regs
[16] == SYS_exit
)
84 tohost_exit(regs
[18]);
85 else if (regs
[16] == SYS_stats
)
86 sys_ret
= handle_stats(regs
[18]);
88 sys_ret
= handle_frontend_syscall(regs
[16], regs
[18], regs
[19], regs
[20]);
94 static long syscall(long num
, long arg0
, long arg1
, long arg2
)
96 register long v0
asm("v0") = num
;
97 register long a0
asm("a0") = arg0
;
98 register long a1
asm("a1") = arg1
;
99 register long a2
asm("a2") = arg2
;
100 asm volatile ("scall" : "+r"(v0
) : "r"(a0
), "r"(a1
), "r"(a2
) : "s0");
106 syscall(SYS_exit
, code
, 0, 0);
109 void setStats(int enable
)
111 syscall(SYS_stats
, enable
, 0, 0);
114 void printstr(const char* s
)
116 syscall(SYS_write
, 1, (long)s
, strlen(s
));
119 void __attribute__((weak
)) thread_entry(int cid
, int nc
)
121 // multi-threaded programs override this function.
122 // for the case of single-threaded programs, only let core 0 proceed.
126 int __attribute__((weak
)) main(int argc
, char** argv
)
128 // single-threaded programs override this function.
129 printstr("Implement main(), foo!\n");
133 void _init(int cid
, int nc
)
135 thread_entry(cid
, nc
);
137 // only single-threaded programs should ever get here.
138 int ret
= main(0, 0);
140 char buf
[NUM_COUNTERS
* 32] __attribute__((aligned(64)));
142 for (int i
= 0; i
< NUM_COUNTERS
; i
++)
144 pbuf
+= sprintf(pbuf
, "%s = %d\n", counter_names
[i
], counters
[i
]);
154 static char buf
[64] __attribute__((aligned(64)));
155 static int buflen
= 0;
159 if (ch
== '\n' || buflen
== sizeof(buf
))
161 syscall(SYS_write
, 1, (long)buf
, buflen
);
168 void printhex(uint64_t x
)
172 for (i
= 0; i
< 16; i
++)
174 str
[15-i
] = (x
& 0xF) + ((x
& 0xF) < 10 ? '0' : 'a'-10);
182 static inline void printnum(void (*putch
)(int, void**), void **putdat
,
183 unsigned long long num
, unsigned base
, int width
, int padc
)
185 unsigned digs
[sizeof(num
)*CHAR_BIT
];
190 digs
[pos
++] = num
% base
;
196 while (width
-- > pos
)
200 putch(digs
[pos
] + (digs
[pos
] >= 10 ? 'a' - 10 : '0'), putdat
);
203 static unsigned long long getuint(va_list *ap
, int lflag
)
206 return va_arg(*ap
, unsigned long long);
208 return va_arg(*ap
, unsigned long);
210 return va_arg(*ap
, unsigned int);
213 static long long getint(va_list *ap
, int lflag
)
216 return va_arg(*ap
, long long);
218 return va_arg(*ap
, long);
220 return va_arg(*ap
, int);
223 static void vprintfmt(void (*putch
)(int, void**), void **putdat
, const char *fmt
, va_list ap
)
225 register const char* p
;
226 const char* last_fmt
;
227 register int ch
, err
;
228 unsigned long long num
;
229 int base
, lflag
, width
, precision
, altflag
;
233 while ((ch
= *(unsigned char *) fmt
) != '%') {
241 // Process a %-escape sequence
249 switch (ch
= *(unsigned char *) fmt
++) {
251 // flag to pad on the right
256 // flag to pad with 0's instead of spaces
271 for (precision
= 0; ; ++fmt
) {
272 precision
= precision
* 10 + ch
- '0';
274 if (ch
< '0' || ch
> '9')
277 goto process_precision
;
280 precision
= va_arg(ap
, int);
281 goto process_precision
;
294 width
= precision
, precision
= -1;
297 // long flag (doubled for long long)
304 putch(va_arg(ap
, int), putdat
);
309 if ((p
= va_arg(ap
, char *)) == NULL
)
311 if (width
> 0 && padc
!= '-')
312 for (width
-= strnlen(p
, precision
); width
> 0; width
--)
314 for (; (ch
= *p
) != '\0' && (precision
< 0 || --precision
>= 0); width
--) {
318 for (; width
> 0; width
--)
324 num
= getint(&ap
, lflag
);
325 if ((long long) num
< 0) {
327 num
= -(long long) num
;
335 goto unsigned_number
;
339 // should do something with padding so it's always 3 octits
341 goto unsigned_number
;
345 static_assert(sizeof(long) == sizeof(void*));
349 /* fall through to 'x' */
351 // (unsigned) hexadecimal
355 num
= getuint(&ap
, lflag
);
357 printnum(putch
, putdat
, num
, base
, width
, padc
);
360 // escaped '%' character
365 // unrecognized escape sequence - just print it literally
374 int printf(const char* fmt
, ...)
379 vprintfmt((void*)putchar
, 0, fmt
, ap
);
382 return 0; // incorrect return value, but who cares, anyway?
385 int sprintf(char* str
, const char* fmt
, ...)
391 void sprintf_putch(int ch
, void** data
)
393 char** pstr
= (char**)data
;
398 vprintfmt(sprintf_putch
, (void**)&str
, fmt
, ap
);