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 46struct rnndelem **elems = NULL; 47int elemsnum = 0; 48int elemsmax = 0; 49 50char **offsetfns = NULL; 51int offsetfnsnum = 0; 52int offsetfnsmax = 0; 53 54int startcol = 64; 55 56struct fout { 57 char *name; 58 FILE *file; 59 char *guard; 60}; 61 62struct fout *fouts = 0; 63int foutsnum = 0; 64int foutsmax = 0; 65 66static bool no_asserts = false; 67 68static 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 84static 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 96static 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 120static 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 127static void printbitfield (struct rnnbitfield *bf, int shift); 128 129static 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 228static 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 234static 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 349static 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 356static 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 365static 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 421int 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