• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 		len = fprintf (dst, "#define %s__%s", name, suf);
101 	else
102 		len = fprintf (dst, "#define %s", name);
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(&regname, "REG_%s_%s", elem->fullname, str);
256 		} else {
257 			asprintf(&regname, "REG_%s", elem->fullname);
258 		}
259 		if (elemsnum) {
260 			FILE *dst = findfout(elem->file);
261 			int i;
262 
263 			if (use_offset_fxn) {
264 				fprintf(dst, "static inline uint32_t %s(", offsetfn);
265 				if (elem->index)
266 					fprintf(dst, "enum %s", elem->index->name);
267 				else
268 					fprintf(dst, "uint32_t");
269 				fprintf(dst, " idx)\n");
270 				fprintf(dst, "{\n");
271 				if (elem->doffset) {
272 					fprintf(dst, "\treturn (%s) + (%#" PRIx64 "*idx);\n", elem->doffset, elem->stride);
273 				} else {
274 					int valuesnum = elem->doffsets ? elem->doffsetsnum : elem->offsetsnum;
275 
276 					fprintf(dst, "\tswitch (idx) {\n");
277 					for (i = 0; i < valuesnum; i++) {
278 						struct rnnvalue *val = NULL;
279 						fprintf(dst, "\t\tcase ");
280 						if (elem->index) {
281 							int j;
282 							for (j = 0; j < elem->index->valsnum; j++) {
283 								if (elem->index->vals[j]->value == i) {
284 									val = elem->index->vals[j];
285 									break;
286 								}
287 							}
288 						}
289 						if (val) {
290 							fprintf(dst, "%s", val->name);
291 						} else {
292 							fprintf(dst, "%d", i);
293 						}
294 						if (elem->offsets) {
295 							fprintf(dst, ": return 0x%08"PRIx64";\n", elem->offsets[i]);
296 						} else {
297 							fprintf(dst, ": return (%s);\n", elem->doffsets[i]);
298 						}
299 					}
300 					fprintf(dst, "\t\tdefault: return INVALID_IDX(idx);\n");
301 					fprintf(dst, "\t}\n");
302 				}
303 				fprintf(dst, "}\n");
304 			}
305 			fprintf (dst, "static inline uint32_t %s(", regname);
306 			for (i = 0; i < elemsnum; i++) {
307 				if (i)
308 					fprintf(dst, ", ");
309 				if (elems[i]->index)
310 					fprintf(dst, "enum %s ", elems[i]->index->name);
311 				else
312 					fprintf(dst, "uint32_t ");
313 				fprintf (dst, "i%d", i);
314 			}
315 			fprintf (dst, ") { return ");
316 			fprintf (dst, "0x%08"PRIx64"", offset + elem->offset);
317 			for (i = 0; i < elemsnum; i++) {
318 				if (offsetfns[i])
319 					fprintf(dst, " + %s(i%d)", offsetfns[i], i);
320 				else
321 					fprintf (dst, " + %#" PRIx64 "*i%d", elems[i]->stride, i);
322 			}
323 			fprintf (dst, "; }\n");
324 		} else
325 			printdef (regname, 0, 0, offset + elem->offset, elem->file);
326 
327 		free(regname);
328 /*
329 		if (elem->stride)
330 			printdef (elem->fullname, "ESIZE", 0, elem->stride, elem->file);
331 		if (elem->length != 1)
332 			printdef (elem->fullname, "LEN", 0, elem->length, elem->file);
333 */
334 		printtypeinfo (&elem->typeinfo, NULL, elem->fullname, elem->file);
335 	}
336 	fprintf (findfout(elem->file), "\n");
337 	int j;
338 	for (j = 0; j < elem->subelemsnum; j++) {
339 		printdelem(elem->subelems[j], offset + elem->offset, elem->varinfo.prefixstr);
340 	}
341 	if (elem->length != 1) {
342 		elemsnum--;
343 		offsetfnsnum--;
344 	}
345 	free(offsetfn);
346 }
347 
print_file_info_(FILE * dst,struct stat * sb,struct tm * tm)348 static void print_file_info_(FILE *dst, struct stat* sb, struct tm* tm)
349 {
350 	char timestr[64];
351 	strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tm);
352 	fprintf(dst, "(%7Lu bytes, from %s)\n", (unsigned long long)sb->st_size, timestr);
353 }
354 
print_file_info(FILE * dst,const char * file)355 static void print_file_info(FILE *dst, const char* file)
356 {
357 	struct stat sb;
358 	struct tm tm;
359 	stat(file, &sb);
360 	gmtime_r(&sb.st_mtime, &tm);
361 	print_file_info_(dst, &sb, &tm);
362 }
363 
printhead(struct fout f,struct rnndb * db)364 static void printhead(struct fout f, struct rnndb *db) {
365 	int i, j;
366 	struct stat sb;
367 	struct tm tm;
368 	stat(f.name, &sb);
369 	gmtime_r(&sb.st_mtime, &tm);
370 	fprintf (f.file, "#ifndef %s\n", f.guard);
371 	fprintf (f.file, "#define %s\n", f.guard);
372 	fprintf (f.file, "\n");
373 	fprintf(f.file,
374 		"/* Autogenerated file, DO NOT EDIT manually!\n"
375 		"\n"
376 		"This file was generated by the rules-ng-ng headergen tool in this git repository:\n"
377 		"http://github.com/freedreno/envytools/\n"
378 		"git clone https://github.com/freedreno/envytools.git\n"
379 		"\n"
380 		"The rules-ng-ng source files this header was generated from are:\n");
381 	unsigned maxlen = 0;
382 	for(i = 0; i < db->filesnum; ++i) {
383 		unsigned len = strlen(db->files[i]);
384 		if(len > maxlen)
385 			maxlen = len;
386 	}
387 	for(i = 0; i < db->filesnum; ++i) {
388 		unsigned len = strlen(db->files[i]);
389 		fprintf(f.file, "- %s%*s ", db->files[i], maxlen - len, "");
390 		print_file_info(f.file, db->files[i]);
391 	}
392 	fprintf(f.file,
393 		"\n"
394 		"Copyright (C) ");
395 	if(db->copyright.firstyear && db->copyright.firstyear < (1900 + tm.tm_year))
396 		fprintf(f.file, "%u-", db->copyright.firstyear);
397 	fprintf(f.file, "%u", 1900 + tm.tm_year);
398 	if(db->copyright.authorsnum) {
399 		fprintf(f.file, " by the following authors:");
400 		for(i = 0; i < db->copyright.authorsnum; ++i) {
401 			fprintf(f.file, "\n- ");
402 			if(db->copyright.authors[i]->name)
403 				fprintf(f.file, "%s", db->copyright.authors[i]->name);
404 			if(db->copyright.authors[i]->email)
405 				fprintf(f.file, " <%s>", db->copyright.authors[i]->email);
406 			if(db->copyright.authors[i]->nicknamesnum) {
407 				for(j = 0; j < db->copyright.authors[i]->nicknamesnum; ++j) {
408 					fprintf(f.file, "%s%s", (j ? ", " : " ("), db->copyright.authors[i]->nicknames[j]);
409 				}
410 				fprintf(f.file, ")");
411 			}
412 		}
413 	}
414 	fprintf(f.file, "\n");
415 	if(db->copyright.license)
416 		fprintf(f.file, "\n%s\n", db->copyright.license);
417 	fprintf(f.file, "*/\n\n\n");
418 }
419 
main(int argc,char ** argv)420 int main(int argc, char **argv) {
421 	char *file;
422 	struct rnndb *db;
423 	int i, j;
424 
425 	if (argc < 2) {
426 		fprintf(stderr, "Usage:\n\theadergen database-file\n");
427 		exit(1);
428 	}
429 
430 	if ((argc >= 3) && !strcmp(argv[1], "--no-asserts")) {
431 		no_asserts = true;
432 		file = argv[2];
433 	} else {
434 		file = argv[1];
435 	}
436 
437 	rnn_init();
438 	db = rnn_newdb();
439 	rnn_parsefile (db, file);
440 	rnn_prepdb (db);
441 	for(i = 0; i < db->filesnum; ++i) {
442 		char *dstname = malloc(strlen(db->files[i]) + 3);
443 		char *pretty;
444 		strcpy(dstname, db->files[i]);
445 		strcat(dstname, ".h");
446 		struct fout f = { db->files[i], fopen(dstname, "w") };
447 		if (!f.file) {
448 			perror(dstname);
449 			exit(1);
450 		}
451 		free(dstname);
452 		pretty = strrchr(f.name, '/');
453 		if (pretty)
454 			pretty += 1;
455 		else
456 			pretty = f.name;
457 		f.guard = strdup(pretty);
458 		for (j = 0; j < strlen(f.guard); j++)
459 			if (isalnum(f.guard[j]))
460 				f.guard[j] = toupper(f.guard[j]);
461 			else
462 				f.guard[j] = '_';
463 		ADDARRAY(fouts, f);
464 		printhead(f, db);
465 	}
466 
467 	for (i = 0; i < db->enumsnum; i++) {
468 		FILE *dst = NULL;
469 		int j;
470 		for (j = 0; j < db->enums[i]->valsnum; j++) {
471 			if (!dst) {
472 				dst = findfout(db->enums[i]->vals[j]->file);
473 				fprintf(dst, "enum %s {\n", db->enums[i]->name);
474 			}
475 			if (0xffff0000 & db->enums[i]->vals[j]->value)
476 				fprintf(dst, "\t%s = 0x%08"PRIx64",\n", db->enums[i]->vals[j]->name,
477 						db->enums[i]->vals[j]->value);
478 			else
479 				fprintf(dst, "\t%s = %"PRIu64",\n", db->enums[i]->vals[j]->name,
480 						db->enums[i]->vals[j]->value);
481 		}
482 		if (dst) {
483 			fprintf(dst, "};\n\n");
484 		}
485 	}
486 	for (i = 0; i < db->bitsetsnum; i++) {
487 		if (db->bitsets[i]->isinline)
488 			continue;
489 		int j;
490 		for (j = 0; j < db->bitsets[i]->bitfieldsnum; j++)
491 			printbitfield (db->bitsets[i]->bitfields[j], 0);
492 	}
493 	for (i = 0; i < db->domainsnum; i++) {
494 		if (db->domains[i]->size)
495 			printdef (db->domains[i]->fullname, "SIZE", 0, db->domains[i]->size, db->domains[i]->file);
496 		int j;
497 		for (j = 0; j < db->domains[i]->subelemsnum; j++) {
498 			printdelem(db->domains[i]->subelems[j], 0, NULL);
499 		}
500 	}
501 	for(i = 0; i < foutsnum; ++i) {
502 		fprintf (fouts[i].file, "\n#endif /* %s */\n", fouts[i].guard);
503 	}
504 	return db->estatus;
505 }
506