1a533497752000608ca816df80090e8784a26bde
[riscv-tests.git] / benchmarks / common / syscalls.c
1 #include <stdint.h>
2 #include <string.h>
3 #include <stdarg.h>
4 #include <stdio.h>
5 #include <limits.h>
6 #include <machine/syscall.h>
7 #include "encoding.h"
8
9 #define static_assert(cond) switch(0) { case 0: case !!(long)(cond): ; }
10
11 void syscall(long which, long arg0, long arg1, long arg2)
12 {
13 volatile uint64_t magic_mem[8] __attribute__((aligned(64)));
14 magic_mem[0] = which;
15 magic_mem[1] = arg0;
16 magic_mem[2] = arg1;
17 magic_mem[3] = arg2;
18 __sync_synchronize();
19 write_csr(tohost, (long)magic_mem);
20 while (swap_csr(fromhost, 0) == 0);
21 }
22
23 void exit(int code)
24 {
25 write_csr(tohost, (code << 1) | 1);
26 while (1);
27 }
28
29 void printstr(const char* s)
30 {
31 syscall(SYS_write, 1, (long)s, strlen(s));
32 }
33
34 // In setStats, we might trap reading uarch-specific counters.
35 // The trap handler will skip over the instruction, but we want
36 // to pretend as though we read the value 0 in this case.
37 #define read_csr_safe(reg) ({ long __tmp = 0; \
38 asm volatile ("csrr %0, " #reg : "+r"(__tmp)); \
39 __tmp; })
40
41 #define NUM_COUNTERS 18
42 static long counters[NUM_COUNTERS];
43 static char* counter_names[NUM_COUNTERS];
44 void setStats(int enable)
45 {
46 int i = 0;
47 #define READ_CTR(name) do { \
48 if (i >= NUM_COUNTERS) exit(-1); \
49 long csr = read_csr_safe(name); \
50 if (!enable) { csr -= counters[i]; counter_names[i] = #name; } \
51 counters[i++] = csr; \
52 } while (0)
53 READ_CTR(cycle); READ_CTR(instret);
54 READ_CTR(uarch0); READ_CTR(uarch1); READ_CTR(uarch2); READ_CTR(uarch3);
55 READ_CTR(uarch4); READ_CTR(uarch5); READ_CTR(uarch6); READ_CTR(uarch7);
56 READ_CTR(uarch8); READ_CTR(uarch9); READ_CTR(uarch10); READ_CTR(uarch11);
57 READ_CTR(uarch12); READ_CTR(uarch13); READ_CTR(uarch14); READ_CTR(uarch15);
58 #undef READ_CTR
59 }
60
61 void __attribute__((weak)) thread_entry(int cid, int nc)
62 {
63 // multi-threaded programs override this function.
64 // for the case of single-threaded programs, only let core 0 proceed.
65 while (cid != 0);
66 }
67
68 int __attribute__((weak)) main(int argc, char** argv)
69 {
70 // single-threaded programs override this function.
71 printstr("Implement main(), foo!\n");
72 return -1;
73 }
74
75 void _init(int cid, int nc)
76 {
77 thread_entry(cid, nc);
78
79 // only single-threaded programs should ever get here.
80 int ret = main(0, 0);
81
82 char buf[NUM_COUNTERS * 32] __attribute__((aligned(64)));
83 char* pbuf = buf;
84 for (int i = 0; i < NUM_COUNTERS; i++)
85 if (counters[i])
86 pbuf += sprintf(pbuf, "%s = %d\n", counter_names[i], counters[i]);
87 if (pbuf != buf)
88 printstr(buf);
89
90 exit(ret);
91 }
92
93 #undef putchar
94 int putchar(int ch)
95 {
96 static char buf[64] __attribute__((aligned(64)));
97 static int buflen = 0;
98
99 buf[buflen++] = ch;
100
101 if (ch == '\n' || buflen == sizeof(buf))
102 {
103 syscall(SYS_write, 1, (long)buf, buflen);
104 buflen = 0;
105 }
106
107 return 0;
108 }
109
110 void printhex(uint64_t x)
111 {
112 char str[17];
113 int i;
114 for (i = 0; i < 16; i++)
115 {
116 str[15-i] = (x & 0xF) + ((x & 0xF) < 10 ? '0' : 'a'-10);
117 x >>= 4;
118 }
119 str[16] = 0;
120
121 printstr(str);
122 }
123
124 static inline void printnum(void (*putch)(int, void**), void **putdat,
125 unsigned long long num, unsigned base, int width, int padc)
126 {
127 unsigned digs[sizeof(num)*CHAR_BIT];
128 int pos = 0;
129
130 while (1)
131 {
132 digs[pos++] = num % base;
133 if (num < base)
134 break;
135 num /= base;
136 }
137
138 while (width-- > pos)
139 putch(padc, putdat);
140
141 while (pos-- > 0)
142 putch(digs[pos] + (digs[pos] >= 10 ? 'a' - 10 : '0'), putdat);
143 }
144
145 static unsigned long long getuint(va_list *ap, int lflag)
146 {
147 if (lflag >= 2)
148 return va_arg(*ap, unsigned long long);
149 else if (lflag)
150 return va_arg(*ap, unsigned long);
151 else
152 return va_arg(*ap, unsigned int);
153 }
154
155 static long long getint(va_list *ap, int lflag)
156 {
157 if (lflag >= 2)
158 return va_arg(*ap, long long);
159 else if (lflag)
160 return va_arg(*ap, long);
161 else
162 return va_arg(*ap, int);
163 }
164
165 static void vprintfmt(void (*putch)(int, void**), void **putdat, const char *fmt, va_list ap)
166 {
167 register const char* p;
168 const char* last_fmt;
169 register int ch, err;
170 unsigned long long num;
171 int base, lflag, width, precision, altflag;
172 char padc;
173
174 while (1) {
175 while ((ch = *(unsigned char *) fmt) != '%') {
176 if (ch == '\0')
177 return;
178 fmt++;
179 putch(ch, putdat);
180 }
181 fmt++;
182
183 // Process a %-escape sequence
184 last_fmt = fmt;
185 padc = ' ';
186 width = -1;
187 precision = -1;
188 lflag = 0;
189 altflag = 0;
190 reswitch:
191 switch (ch = *(unsigned char *) fmt++) {
192
193 // flag to pad on the right
194 case '-':
195 padc = '-';
196 goto reswitch;
197
198 // flag to pad with 0's instead of spaces
199 case '0':
200 padc = '0';
201 goto reswitch;
202
203 // width field
204 case '1':
205 case '2':
206 case '3':
207 case '4':
208 case '5':
209 case '6':
210 case '7':
211 case '8':
212 case '9':
213 for (precision = 0; ; ++fmt) {
214 precision = precision * 10 + ch - '0';
215 ch = *fmt;
216 if (ch < '0' || ch > '9')
217 break;
218 }
219 goto process_precision;
220
221 case '*':
222 precision = va_arg(ap, int);
223 goto process_precision;
224
225 case '.':
226 if (width < 0)
227 width = 0;
228 goto reswitch;
229
230 case '#':
231 altflag = 1;
232 goto reswitch;
233
234 process_precision:
235 if (width < 0)
236 width = precision, precision = -1;
237 goto reswitch;
238
239 // long flag (doubled for long long)
240 case 'l':
241 lflag++;
242 goto reswitch;
243
244 // character
245 case 'c':
246 putch(va_arg(ap, int), putdat);
247 break;
248
249 // string
250 case 's':
251 if ((p = va_arg(ap, char *)) == NULL)
252 p = "(null)";
253 if (width > 0 && padc != '-')
254 for (width -= strnlen(p, precision); width > 0; width--)
255 putch(padc, putdat);
256 for (; (ch = *p) != '\0' && (precision < 0 || --precision >= 0); width--) {
257 putch(ch, putdat);
258 p++;
259 }
260 for (; width > 0; width--)
261 putch(' ', putdat);
262 break;
263
264 // (signed) decimal
265 case 'd':
266 num = getint(&ap, lflag);
267 if ((long long) num < 0) {
268 putch('-', putdat);
269 num = -(long long) num;
270 }
271 base = 10;
272 goto signed_number;
273
274 // unsigned decimal
275 case 'u':
276 base = 10;
277 goto unsigned_number;
278
279 // (unsigned) octal
280 case 'o':
281 // should do something with padding so it's always 3 octits
282 base = 8;
283 goto unsigned_number;
284
285 // pointer
286 case 'p':
287 static_assert(sizeof(long) == sizeof(void*));
288 lflag = 1;
289 putch('0', putdat);
290 putch('x', putdat);
291 /* fall through to 'x' */
292
293 // (unsigned) hexadecimal
294 case 'x':
295 base = 16;
296 unsigned_number:
297 num = getuint(&ap, lflag);
298 signed_number:
299 printnum(putch, putdat, num, base, width, padc);
300 break;
301
302 // escaped '%' character
303 case '%':
304 putch(ch, putdat);
305 break;
306
307 // unrecognized escape sequence - just print it literally
308 default:
309 putch('%', putdat);
310 fmt = last_fmt;
311 break;
312 }
313 }
314 }
315
316 int printf(const char* fmt, ...)
317 {
318 va_list ap;
319 va_start(ap, fmt);
320
321 vprintfmt((void*)putchar, 0, fmt, ap);
322
323 va_end(ap);
324 return 0; // incorrect return value, but who cares, anyway?
325 }
326
327 int sprintf(char* str, const char* fmt, ...)
328 {
329 va_list ap;
330 char* str0 = str;
331 va_start(ap, fmt);
332
333 void sprintf_putch(int ch, void** data)
334 {
335 char** pstr = (char**)data;
336 **pstr = ch;
337 (*pstr)++;
338 }
339
340 vprintfmt(sprintf_putch, (void**)&str, fmt, ap);
341 *str = 0;
342
343 va_end(ap);
344 return str - str0;
345 }