Change the global pointer symbol to __global_pointer$
[riscv-tests.git] / benchmarks / common / syscalls.c
1 // See LICENSE for license details.
2
3 #include <stdint.h>
4 #include <string.h>
5 #include <stdarg.h>
6 #include <stdio.h>
7 #include <limits.h>
8 #include "util.h"
9
10 #define SYS_write 64
11
12 #undef strcmp
13
14 extern volatile uint64_t tohost;
15 extern volatile uint64_t fromhost;
16
17 static uintptr_t syscall(uintptr_t which, uint64_t arg0, uint64_t arg1, uint64_t arg2)
18 {
19 volatile uint64_t magic_mem[8] __attribute__((aligned(64)));
20 magic_mem[0] = which;
21 magic_mem[1] = arg0;
22 magic_mem[2] = arg1;
23 magic_mem[3] = arg2;
24 __sync_synchronize();
25
26 tohost = (uintptr_t)magic_mem;
27 while (fromhost == 0)
28 ;
29 fromhost = 0;
30
31 __sync_synchronize();
32 return magic_mem[0];
33 }
34
35 #define NUM_COUNTERS 2
36 static uintptr_t counters[NUM_COUNTERS];
37 static char* counter_names[NUM_COUNTERS];
38
39 void setStats(int enable)
40 {
41 int i = 0;
42 #define READ_CTR(name) do { \
43 while (i >= NUM_COUNTERS) ; \
44 uintptr_t csr = read_csr(name); \
45 if (!enable) { csr -= counters[i]; counter_names[i] = #name; } \
46 counters[i++] = csr; \
47 } while (0)
48
49 READ_CTR(mcycle);
50 READ_CTR(minstret);
51
52 #undef READ_CTR
53 }
54
55 void __attribute__((noreturn)) tohost_exit(uintptr_t code)
56 {
57 tohost = (code << 1) | 1;
58 while (1);
59 }
60
61 uintptr_t __attribute__((weak)) handle_trap(uintptr_t cause, uintptr_t epc, uintptr_t regs[32])
62 {
63 tohost_exit(1337);
64 }
65
66 void exit(int code)
67 {
68 tohost_exit(code);
69 }
70
71 void printstr(const char* s)
72 {
73 syscall(SYS_write, 1, (uintptr_t)s, strlen(s));
74 }
75
76 void __attribute__((weak)) thread_entry(int cid, int nc)
77 {
78 // multi-threaded programs override this function.
79 // for the case of single-threaded programs, only let core 0 proceed.
80 while (cid != 0);
81 }
82
83 int __attribute__((weak)) main(int argc, char** argv)
84 {
85 // single-threaded programs override this function.
86 printstr("Implement main(), foo!\n");
87 return -1;
88 }
89
90 static void init_tls()
91 {
92 register void* thread_pointer asm("tp");
93 extern char _tls_data;
94 extern __thread char _tdata_begin, _tdata_end, _tbss_end;
95 size_t tdata_size = &_tdata_end - &_tdata_begin;
96 memcpy(thread_pointer, &_tls_data, tdata_size);
97 size_t tbss_size = &_tbss_end - &_tdata_end;
98 memset(thread_pointer + tdata_size, 0, tbss_size);
99 }
100
101 void _init(int cid, int nc)
102 {
103 init_tls();
104 thread_entry(cid, nc);
105
106 // only single-threaded programs should ever get here.
107 int ret = main(0, 0);
108
109 char buf[NUM_COUNTERS * 32] __attribute__((aligned(64)));
110 char* pbuf = buf;
111 for (int i = 0; i < NUM_COUNTERS; i++)
112 if (counters[i])
113 pbuf += sprintf(pbuf, "%s = %d\n", counter_names[i], counters[i]);
114 if (pbuf != buf)
115 printstr(buf);
116
117 exit(ret);
118 }
119
120 #undef putchar
121 int putchar(int ch)
122 {
123 static __thread char buf[64] __attribute__((aligned(64)));
124 static __thread int buflen = 0;
125
126 buf[buflen++] = ch;
127
128 if (ch == '\n' || buflen == sizeof(buf))
129 {
130 syscall(SYS_write, 1, (uintptr_t)buf, buflen);
131 buflen = 0;
132 }
133
134 return 0;
135 }
136
137 void printhex(uint64_t x)
138 {
139 char str[17];
140 int i;
141 for (i = 0; i < 16; i++)
142 {
143 str[15-i] = (x & 0xF) + ((x & 0xF) < 10 ? '0' : 'a'-10);
144 x >>= 4;
145 }
146 str[16] = 0;
147
148 printstr(str);
149 }
150
151 static inline void printnum(void (*putch)(int, void**), void **putdat,
152 unsigned long long num, unsigned base, int width, int padc)
153 {
154 unsigned digs[sizeof(num)*CHAR_BIT];
155 int pos = 0;
156
157 while (1)
158 {
159 digs[pos++] = num % base;
160 if (num < base)
161 break;
162 num /= base;
163 }
164
165 while (width-- > pos)
166 putch(padc, putdat);
167
168 while (pos-- > 0)
169 putch(digs[pos] + (digs[pos] >= 10 ? 'a' - 10 : '0'), putdat);
170 }
171
172 static unsigned long long getuint(va_list *ap, int lflag)
173 {
174 if (lflag >= 2)
175 return va_arg(*ap, unsigned long long);
176 else if (lflag)
177 return va_arg(*ap, unsigned long);
178 else
179 return va_arg(*ap, unsigned int);
180 }
181
182 static long long getint(va_list *ap, int lflag)
183 {
184 if (lflag >= 2)
185 return va_arg(*ap, long long);
186 else if (lflag)
187 return va_arg(*ap, long);
188 else
189 return va_arg(*ap, int);
190 }
191
192 static void vprintfmt(void (*putch)(int, void**), void **putdat, const char *fmt, va_list ap)
193 {
194 register const char* p;
195 const char* last_fmt;
196 register int ch, err;
197 unsigned long long num;
198 int base, lflag, width, precision, altflag;
199 char padc;
200
201 while (1) {
202 while ((ch = *(unsigned char *) fmt) != '%') {
203 if (ch == '\0')
204 return;
205 fmt++;
206 putch(ch, putdat);
207 }
208 fmt++;
209
210 // Process a %-escape sequence
211 last_fmt = fmt;
212 padc = ' ';
213 width = -1;
214 precision = -1;
215 lflag = 0;
216 altflag = 0;
217 reswitch:
218 switch (ch = *(unsigned char *) fmt++) {
219
220 // flag to pad on the right
221 case '-':
222 padc = '-';
223 goto reswitch;
224
225 // flag to pad with 0's instead of spaces
226 case '0':
227 padc = '0';
228 goto reswitch;
229
230 // width field
231 case '1':
232 case '2':
233 case '3':
234 case '4':
235 case '5':
236 case '6':
237 case '7':
238 case '8':
239 case '9':
240 for (precision = 0; ; ++fmt) {
241 precision = precision * 10 + ch - '0';
242 ch = *fmt;
243 if (ch < '0' || ch > '9')
244 break;
245 }
246 goto process_precision;
247
248 case '*':
249 precision = va_arg(ap, int);
250 goto process_precision;
251
252 case '.':
253 if (width < 0)
254 width = 0;
255 goto reswitch;
256
257 case '#':
258 altflag = 1;
259 goto reswitch;
260
261 process_precision:
262 if (width < 0)
263 width = precision, precision = -1;
264 goto reswitch;
265
266 // long flag (doubled for long long)
267 case 'l':
268 lflag++;
269 goto reswitch;
270
271 // character
272 case 'c':
273 putch(va_arg(ap, int), putdat);
274 break;
275
276 // string
277 case 's':
278 if ((p = va_arg(ap, char *)) == NULL)
279 p = "(null)";
280 if (width > 0 && padc != '-')
281 for (width -= strnlen(p, precision); width > 0; width--)
282 putch(padc, putdat);
283 for (; (ch = *p) != '\0' && (precision < 0 || --precision >= 0); width--) {
284 putch(ch, putdat);
285 p++;
286 }
287 for (; width > 0; width--)
288 putch(' ', putdat);
289 break;
290
291 // (signed) decimal
292 case 'd':
293 num = getint(&ap, lflag);
294 if ((long long) num < 0) {
295 putch('-', putdat);
296 num = -(long long) num;
297 }
298 base = 10;
299 goto signed_number;
300
301 // unsigned decimal
302 case 'u':
303 base = 10;
304 goto unsigned_number;
305
306 // (unsigned) octal
307 case 'o':
308 // should do something with padding so it's always 3 octits
309 base = 8;
310 goto unsigned_number;
311
312 // pointer
313 case 'p':
314 static_assert(sizeof(long) == sizeof(void*));
315 lflag = 1;
316 putch('0', putdat);
317 putch('x', putdat);
318 /* fall through to 'x' */
319
320 // (unsigned) hexadecimal
321 case 'x':
322 base = 16;
323 unsigned_number:
324 num = getuint(&ap, lflag);
325 signed_number:
326 printnum(putch, putdat, num, base, width, padc);
327 break;
328
329 // escaped '%' character
330 case '%':
331 putch(ch, putdat);
332 break;
333
334 // unrecognized escape sequence - just print it literally
335 default:
336 putch('%', putdat);
337 fmt = last_fmt;
338 break;
339 }
340 }
341 }
342
343 int printf(const char* fmt, ...)
344 {
345 va_list ap;
346 va_start(ap, fmt);
347
348 vprintfmt((void*)putchar, 0, fmt, ap);
349
350 va_end(ap);
351 return 0; // incorrect return value, but who cares, anyway?
352 }
353
354 int sprintf(char* str, const char* fmt, ...)
355 {
356 va_list ap;
357 char* str0 = str;
358 va_start(ap, fmt);
359
360 void sprintf_putch(int ch, void** data)
361 {
362 char** pstr = (char**)data;
363 **pstr = ch;
364 (*pstr)++;
365 }
366
367 vprintfmt(sprintf_putch, (void**)&str, fmt, ap);
368 *str = 0;
369
370 va_end(ap);
371 return str - str0;
372 }
373
374 void* memcpy(void* dest, const void* src, size_t len)
375 {
376 if ((((uintptr_t)dest | (uintptr_t)src | len) & (sizeof(uintptr_t)-1)) == 0) {
377 const uintptr_t* s = src;
378 uintptr_t *d = dest;
379 while (d < (uintptr_t*)(dest + len))
380 *d++ = *s++;
381 } else {
382 const char* s = src;
383 char *d = dest;
384 while (d < (char*)(dest + len))
385 *d++ = *s++;
386 }
387 return dest;
388 }
389
390 void* memset(void* dest, int byte, size_t len)
391 {
392 if ((((uintptr_t)dest | len) & (sizeof(uintptr_t)-1)) == 0) {
393 uintptr_t word = byte & 0xFF;
394 word |= word << 8;
395 word |= word << 16;
396 word |= word << 16 << 16;
397
398 uintptr_t *d = dest;
399 while (d < (uintptr_t*)(dest + len))
400 *d++ = word;
401 } else {
402 char *d = dest;
403 while (d < (char*)(dest + len))
404 *d++ = byte;
405 }
406 return dest;
407 }
408
409 size_t strlen(const char *s)
410 {
411 const char *p = s;
412 while (*p)
413 p++;
414 return p - s;
415 }
416
417 size_t strnlen(const char *s, size_t n)
418 {
419 const char *p = s;
420 while (n-- && *p)
421 p++;
422 return p - s;
423 }
424
425 int strcmp(const char* s1, const char* s2)
426 {
427 unsigned char c1, c2;
428
429 do {
430 c1 = *s1++;
431 c2 = *s2++;
432 } while (c1 != 0 && c1 == c2);
433
434 return c1 - c2;
435 }
436
437 char* strcpy(char* dest, const char* src)
438 {
439 char* d = dest;
440 while ((*d++ = *src++))
441 ;
442 return dest;
443 }
444
445 long atol(const char* str)
446 {
447 long res = 0;
448 int sign = 0;
449
450 while (*str == ' ')
451 str++;
452
453 if (*str == '-' || *str == '+') {
454 sign = *str == '-';
455 str++;
456 }
457
458 while (*str) {
459 res *= 10;
460 res += *str++ - '0';
461 }
462
463 return sign ? -res : res;
464 }