1 /*
2 * Copyright (C) 2013 Rob Clark <robdclark@gmail.com>
3 * Copyright (C) 2010-2011 Marcin Kościelnicki <koriakin@0x04.net>
4 * Copyright (C) 2010 Luca Barbieri <luca@luca-barbieri.com>
5 * Copyright (C) 2010 Marcin Slusarz <marcin.slusarz@gmail.com>
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28 /* modified version of headergen which uses enums and inline fxns for
29 * type safety.. based on original headergen
30 */
31
32 #include "rnn.h"
33 #include "util.h"
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <inttypes.h>
38 #include <time.h>
39 #include <ctype.h>
40 #include <unistd.h>
41 #include <string.h>
42 #include <sys/stat.h>
43 #include <sys/wait.h>
44 #include <assert.h>
45
46 struct rnndelem **elems = NULL;
47 int elemsnum = 0;
48 int elemsmax = 0;
49
50 char **offsetfns = NULL;
51 int offsetfnsnum = 0;
52 int offsetfnsmax = 0;
53
54 int startcol = 64;
55
56 struct fout {
57 char *name;
58 FILE *file;
59 char *guard;
60 };
61
62 struct fout *fouts = 0;
63 int foutsnum = 0;
64 int foutsmax = 0;
65
66 static bool no_asserts = false;
67
seekcol(FILE * f,int src,int dst)68 static void seekcol (FILE *f, int src, int dst) {
69 if (dst <= src)
70 fprintf (f, "\t");
71 else {
72 int n = dst/8 - src/8;
73 if (n) {
74 while (n--)
75 fprintf (f, "\t");
76 n = dst&7;
77 } else
78 n = dst-src;
79 while (n--)
80 fprintf (f, " ");
81 }
82 }
83
findfout(char * file)84 static FILE *findfout (char *file) {
85 int i;
86 for (i = 0; i < foutsnum; i++)
87 if (!strcmp(fouts[i].name, file))
88 break;
89 if (i == foutsnum) {
90 fprintf (stderr, "AIII, didn't open file %s.\n", file);
91 exit(1);
92 }
93 return fouts[i].file;
94 }
95
printdef(char * name,char * suf,int type,uint64_t val,char * file)96 static void printdef (char *name, char *suf, int type, uint64_t val, char *file) {
97 FILE *dst = findfout(file);
98 int len;
99 if (suf)
100 fprintf (dst, "#define %s__%s%n", name, suf, &len);
101 else
102 fprintf (dst, "#define %s%n", name, &len);
103 if (type == 0 && val > 0xffffffffull)
104 seekcol (dst, len, startcol-8);
105 else
106 seekcol (dst, len, startcol);
107 switch (type) {
108 case 0:
109 if (val > 0xffffffffull)
110 fprintf (dst, "0x%016"PRIx64"ULL\n", val);
111 else
112 fprintf (dst, "0x%08"PRIx64"\n", val);
113 break;
114 case 1:
115 fprintf (dst, "%"PRIu64"\n", val);
116 break;
117 }
118 }
119
printvalue(struct rnnvalue * val,int shift)120 static void printvalue (struct rnnvalue *val, int shift) {
121 if (val->varinfo.dead)
122 return;
123 if (val->valvalid)
124 printdef (val->fullname, 0, 0, val->value << shift, val->file);
125 }
126
127 static void printbitfield (struct rnnbitfield *bf, int shift);
128
printtypeinfo(struct rnntypeinfo * ti,struct rnnbitfield * bf,char * prefix,char * file)129 static void printtypeinfo (struct rnntypeinfo *ti, struct rnnbitfield *bf,
130 char *prefix, char *file) {
131 FILE *dst = findfout(file);
132 enum rnnttype intype = ti->type;
133 char *typename = NULL;
134 uint32_t mask = typeinfo_mask(ti);
135 uint32_t width = 1 + ti->high - ti->low;
136
137 /* for fixed point, input type (arg to fxn) is float: */
138 if ((ti->type == RNN_TTYPE_FIXED) || (ti->type == RNN_TTYPE_UFIXED))
139 intype = RNN_TTYPE_FLOAT;
140
141 /* for toplevel register (ie. not bitfield), only generate accessor
142 * fxn for special cases (float, shr, min/max, etc):
143 */
144 if (bf || ti->shr || ti->minvalid || ti->maxvalid || ti->alignvalid ||
145 ti->radixvalid || (intype == RNN_TTYPE_FLOAT)) {
146 switch (intype) {
147 case RNN_TTYPE_HEX:
148 case RNN_TTYPE_UINT:
149 case RNN_TTYPE_A3XX_REGID:
150 typename = "uint32_t";
151 break;
152 case RNN_TTYPE_INT:
153 typename = "int32_t";
154 break;
155 case RNN_TTYPE_FLOAT:
156 typename = "float";
157 break;
158 case RNN_TTYPE_ENUM:
159 asprintf(&typename, "enum %s", ti->name);
160 break;
161 default:
162 break;
163 }
164 }
165
166 /* for boolean, just generate a #define flag.. rather than inline fxn */
167 if (bf && (intype == RNN_TTYPE_BOOLEAN)) {
168 printdef(bf->fullname, 0, 0, mask, file);
169 return;
170 }
171
172 if (typename) {
173 printdef(prefix, "MASK", 0, mask, file);
174 printdef(prefix, "SHIFT", 1, ti->low, file);
175
176 fprintf(dst, "static inline uint32_t %s(%s val)\n", prefix, typename);
177 fprintf(dst, "{\n");
178
179 if ((ti->minvalid || ti->maxvalid || ti->alignvalid) && !no_asserts) {
180 fprintf(dst, "\tassert(1");
181 if (ti->minvalid)
182 fprintf(dst, " && (val >= %"PRIu64")", ti->min);
183 if (ti->maxvalid)
184 fprintf(dst, " && (val <= %"PRIu64")", ti->max);
185 if (ti->alignvalid)
186 fprintf(dst, " && !(val %% %"PRIu64")", ti->align);
187 fprintf(dst, ");\n");
188 }
189
190 if (ti->shr && !no_asserts) {
191 fprintf(dst, "\tassert(!(val & 0x%x));\n", (1 << ti->shr) - 1);
192 }
193
194 fprintf(dst, "\treturn ((");
195
196 if (ti->type == RNN_TTYPE_FIXED) {
197 fprintf(dst, "((int32_t)(val * %d.0))", (1 << ti->radix));
198 } else if (ti->type == RNN_TTYPE_UFIXED) {
199 fprintf(dst, "((uint32_t)(val * %d.0))", (1 << ti->radix));
200 } else if (ti->type == RNN_TTYPE_FLOAT) {
201 if (width == 32)
202 fprintf(dst, "fui(val)");
203 else if (width == 16)
204 fprintf(dst, "_mesa_float_to_half(val)");
205 else
206 assert(!"invalid float size");
207 } else {
208 fprintf(dst, "val");
209 }
210
211 if (ti->shr)
212 fprintf(dst, " >> %d", ti->shr);
213
214 fprintf(dst, ") << %s__SHIFT) & %s__MASK;\n", prefix, prefix);
215 fprintf(dst, "}\n");
216
217 if (intype == RNN_TTYPE_ENUM)
218 free(typename);
219 }
220
221 int i;
222 for (i = 0; i < ti->valsnum; i++)
223 printvalue(ti->vals[i], ti->low);
224 for (i = 0; i < ti->bitfieldsnum; i++)
225 printbitfield(ti->bitfields[i], ti->low);
226 }
227
printbitfield(struct rnnbitfield * bf,int shift)228 static void printbitfield (struct rnnbitfield *bf, int shift) {
229 if (bf->varinfo.dead)
230 return;
231 printtypeinfo (&bf->typeinfo, bf, bf->fullname, bf->file);
232 }
233
printdelem(struct rnndelem * elem,uint64_t offset,const char * str)234 static void printdelem (struct rnndelem *elem, uint64_t offset, const char *str) {
235 int use_offset_fxn;
236 char *offsetfn = NULL;
237
238 if (elem->varinfo.dead)
239 return;
240
241 use_offset_fxn = elem->offsets || elem->doffset || elem->doffsets;
242 assert((!!elem->offsets + !!elem->doffset + !!elem->doffsets) <= 1);
243
244 if (use_offset_fxn)
245 asprintf(&offsetfn, "__offset_%s", elem->name);
246
247 if (elem->length != 1) {
248 ADDARRAY(elems, elem);
249 ADDARRAY(offsetfns, offsetfn);
250 }
251
252 if (elem->name) {
253 char *regname;
254 if (str) {
255 asprintf(®name, "REG_%s_%s", elem->fullname, str);
256 } else {
257 asprintf(®name, "REG_%s", elem->fullname);
258 }
259 if (elemsnum) {
260 int len;
261 FILE *dst = findfout(elem->file);
262 int i;
263
264 if (use_offset_fxn) {
265 fprintf(dst, "static inline uint32_t %s(", offsetfn);
266 if (elem->index)
267 fprintf(dst, "enum %s", elem->index->name);
268 else
269 fprintf(dst, "uint32_t");
270 fprintf(dst, " idx)\n");
271 fprintf(dst, "{\n");
272 if (elem->doffset) {
273 fprintf(dst, "\treturn (%s) + (%#" PRIx64 "*idx);\n", elem->doffset, elem->stride);
274 } else {
275 int valuesnum = elem->doffsets ? elem->doffsetsnum : elem->offsetsnum;
276
277 fprintf(dst, "\tswitch (idx) {\n");
278 for (i = 0; i < valuesnum; i++) {
279 struct rnnvalue *val = NULL;
280 fprintf(dst, "\t\tcase ");
281 if (elem->index) {
282 int j;
283 for (j = 0; j < elem->index->valsnum; j++) {
284 if (elem->index->vals[j]->value == i) {
285 val = elem->index->vals[j];
286 break;
287 }
288 }
289 }
290 if (val) {
291 fprintf(dst, "%s", val->name);
292 } else {
293 fprintf(dst, "%d", i);
294 }
295 if (elem->offsets) {
296 fprintf(dst, ": return 0x%08"PRIx64";\n", elem->offsets[i]);
297 } else {
298 fprintf(dst, ": return (%s);\n", elem->doffsets[i]);
299 }
300 }
301 fprintf(dst, "\t\tdefault: return INVALID_IDX(idx);\n");
302 fprintf(dst, "\t}\n");
303 }
304 fprintf(dst, "}\n");
305 }
306 fprintf (dst, "static inline uint32_t %s(", regname);
307 for (i = 0; i < elemsnum; i++) {
308 if (i)
309 fprintf(dst, ", ");
310 if (elems[i]->index)
311 fprintf(dst, "enum %s ", elems[i]->index->name);
312 else
313 fprintf(dst, "uint32_t ");
314 fprintf (dst, "i%d%n", i, &len);
315 }
316 fprintf (dst, ") { return ");
317 fprintf (dst, "0x%08"PRIx64"", offset + elem->offset);
318 for (i = 0; i < elemsnum; i++) {
319 if (offsetfns[i])
320 fprintf(dst, " + %s(i%d)", offsetfns[i], i);
321 else
322 fprintf (dst, " + %#" PRIx64 "*i%d", elems[i]->stride, i);
323 }
324 fprintf (dst, "; }\n");
325 } else
326 printdef (regname, 0, 0, offset + elem->offset, elem->file);
327
328 free(regname);
329 /*
330 if (elem->stride)
331 printdef (elem->fullname, "ESIZE", 0, elem->stride, elem->file);
332 if (elem->length != 1)
333 printdef (elem->fullname, "LEN", 0, elem->length, elem->file);
334 */
335 printtypeinfo (&elem->typeinfo, NULL, elem->fullname, elem->file);
336 }
337 fprintf (findfout(elem->file), "\n");
338 int j;
339 for (j = 0; j < elem->subelemsnum; j++) {
340 printdelem(elem->subelems[j], offset + elem->offset, elem->varinfo.prefixstr);
341 }
342 if (elem->length != 1) {
343 elemsnum--;
344 offsetfnsnum--;
345 }
346 free(offsetfn);
347 }
348
print_file_info_(FILE * dst,struct stat * sb,struct tm * tm)349 static void print_file_info_(FILE *dst, struct stat* sb, struct tm* tm)
350 {
351 char timestr[64];
352 strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tm);
353 fprintf(dst, "(%7Lu bytes, from %s)\n", (unsigned long long)sb->st_size, timestr);
354 }
355
print_file_info(FILE * dst,const char * file)356 static void print_file_info(FILE *dst, const char* file)
357 {
358 struct stat sb;
359 struct tm tm;
360 stat(file, &sb);
361 gmtime_r(&sb.st_mtime, &tm);
362 print_file_info_(dst, &sb, &tm);
363 }
364
printhead(struct fout f,struct rnndb * db)365 static void printhead(struct fout f, struct rnndb *db) {
366 int i, j;
367 struct stat sb;
368 struct tm tm;
369 stat(f.name, &sb);
370 gmtime_r(&sb.st_mtime, &tm);
371 fprintf (f.file, "#ifndef %s\n", f.guard);
372 fprintf (f.file, "#define %s\n", f.guard);
373 fprintf (f.file, "\n");
374 fprintf(f.file,
375 "/* Autogenerated file, DO NOT EDIT manually!\n"
376 "\n"
377 "This file was generated by the rules-ng-ng headergen tool in this git repository:\n"
378 "http://github.com/freedreno/envytools/\n"
379 "git clone https://github.com/freedreno/envytools.git\n"
380 "\n"
381 "The rules-ng-ng source files this header was generated from are:\n");
382 unsigned maxlen = 0;
383 for(i = 0; i < db->filesnum; ++i) {
384 unsigned len = strlen(db->files[i]);
385 if(len > maxlen)
386 maxlen = len;
387 }
388 for(i = 0; i < db->filesnum; ++i) {
389 unsigned len = strlen(db->files[i]);
390 fprintf(f.file, "- %s%*s ", db->files[i], maxlen - len, "");
391 print_file_info(f.file, db->files[i]);
392 }
393 fprintf(f.file,
394 "\n"
395 "Copyright (C) ");
396 if(db->copyright.firstyear && db->copyright.firstyear < (1900 + tm.tm_year))
397 fprintf(f.file, "%u-", db->copyright.firstyear);
398 fprintf(f.file, "%u", 1900 + tm.tm_year);
399 if(db->copyright.authorsnum) {
400 fprintf(f.file, " by the following authors:");
401 for(i = 0; i < db->copyright.authorsnum; ++i) {
402 fprintf(f.file, "\n- ");
403 if(db->copyright.authors[i]->name)
404 fprintf(f.file, "%s", db->copyright.authors[i]->name);
405 if(db->copyright.authors[i]->email)
406 fprintf(f.file, " <%s>", db->copyright.authors[i]->email);
407 if(db->copyright.authors[i]->nicknamesnum) {
408 for(j = 0; j < db->copyright.authors[i]->nicknamesnum; ++j) {
409 fprintf(f.file, "%s%s", (j ? ", " : " ("), db->copyright.authors[i]->nicknames[j]);
410 }
411 fprintf(f.file, ")");
412 }
413 }
414 }
415 fprintf(f.file, "\n");
416 if(db->copyright.license)
417 fprintf(f.file, "\n%s\n", db->copyright.license);
418 fprintf(f.file, "*/\n\n\n");
419 }
420
main(int argc,char ** argv)421 int main(int argc, char **argv) {
422 char *file;
423 struct rnndb *db;
424 int i, j;
425
426 if (argc < 2) {
427 fprintf(stderr, "Usage:\n\theadergen database-file\n");
428 exit(1);
429 }
430
431 if ((argc >= 3) && !strcmp(argv[1], "--no-asserts")) {
432 no_asserts = true;
433 file = argv[2];
434 } else {
435 file = argv[1];
436 }
437
438 rnn_init();
439 db = rnn_newdb();
440 rnn_parsefile (db, file);
441 rnn_prepdb (db);
442 for(i = 0; i < db->filesnum; ++i) {
443 char *dstname = malloc(strlen(db->files[i]) + 3);
444 char *pretty;
445 strcpy(dstname, db->files[i]);
446 strcat(dstname, ".h");
447 struct fout f = { db->files[i], fopen(dstname, "w") };
448 if (!f.file) {
449 perror(dstname);
450 exit(1);
451 }
452 free(dstname);
453 pretty = strrchr(f.name, '/');
454 if (pretty)
455 pretty += 1;
456 else
457 pretty = f.name;
458 f.guard = strdup(pretty);
459 for (j = 0; j < strlen(f.guard); j++)
460 if (isalnum(f.guard[j]))
461 f.guard[j] = toupper(f.guard[j]);
462 else
463 f.guard[j] = '_';
464 ADDARRAY(fouts, f);
465 printhead(f, db);
466 }
467
468 for (i = 0; i < db->enumsnum; i++) {
469 FILE *dst = NULL;
470 int j;
471 for (j = 0; j < db->enums[i]->valsnum; j++) {
472 if (!dst) {
473 dst = findfout(db->enums[i]->vals[j]->file);
474 fprintf(dst, "enum %s {\n", db->enums[i]->name);
475 }
476 if (0xffff0000 & db->enums[i]->vals[j]->value)
477 fprintf(dst, "\t%s = 0x%08"PRIx64",\n", db->enums[i]->vals[j]->name,
478 db->enums[i]->vals[j]->value);
479 else
480 fprintf(dst, "\t%s = %"PRIu64",\n", db->enums[i]->vals[j]->name,
481 db->enums[i]->vals[j]->value);
482 }
483 if (dst) {
484 fprintf(dst, "};\n\n");
485 }
486 }
487 for (i = 0; i < db->bitsetsnum; i++) {
488 if (db->bitsets[i]->isinline)
489 continue;
490 int j;
491 for (j = 0; j < db->bitsets[i]->bitfieldsnum; j++)
492 printbitfield (db->bitsets[i]->bitfields[j], 0);
493 }
494 for (i = 0; i < db->domainsnum; i++) {
495 if (db->domains[i]->size)
496 printdef (db->domains[i]->fullname, "SIZE", 0, db->domains[i]->size, db->domains[i]->file);
497 int j;
498 for (j = 0; j < db->domains[i]->subelemsnum; j++) {
499 printdelem(db->domains[i]->subelems[j], 0, NULL);
500 }
501 }
502 for(i = 0; i < foutsnum; ++i) {
503 fprintf (fouts[i].file, "\n#endif /* %s */\n", fouts[i].guard);
504 }
505 return db->estatus;
506 }
507