|
|
1.1.1.2 ! root 1: /* 1.1 root 2: * UAE - The Un*x Amiga Emulator 1.1.1.2 ! root 3: * 1.1 root 4: * Optimized blitter minterm function generator 1.1.1.2 ! root 5: * 1.1 root 6: * Copyright 1995,1996 Bernd Schmidt 7: * Copyright 1996 Alessandro Bissacco 1.1.1.2 ! root 8: * 1.1 root 9: * Overkill, n: cf. genblitter 10: */ 11: 12: #include "sysconfig.h" 13: #include "sysdeps.h" 14: 15: #include "config.h" 16: #include "options.h" 17: 18: static void nop(int); 19: 20: #define xmalloc malloc 21: #define xfree free 22: #define xrealloc realloc 23: 24: typedef struct tree_n { 1.1.1.2 ! root 25: enum tree_op { op_and, op_or, op_xor, op_not, op_a, op_b, op_c, op_d, op_e, op_f } op; 1.1 root 26: struct tree_n *left, *right; 27: } *tree; 28: 1.1.1.2 ! root 29: static struct tree_n TRA = { op_a, NULL, NULL }; ! 30: static struct tree_n TRB = { op_b, NULL, NULL }; ! 31: static struct tree_n TRC = { op_c, NULL, NULL }; ! 32: static struct tree_n TRD = { op_d, NULL, NULL }; ! 33: static struct tree_n TRE = { op_e, NULL, NULL }; ! 34: static struct tree_n TRF = { op_f, NULL, NULL }; ! 35: static tree tree_a = &TRA; ! 36: static tree tree_b = &TRB; ! 37: static tree tree_c = &TRC; ! 38: static tree tree_d = &TRD; ! 39: static tree tree_e = &TRE; ! 40: static tree tree_f = &TRF; 1.1 root 41: 42: typedef struct { 43: tree *trees; 44: int space; 45: int ntrees; 46: } tree_vec; 47: 1.1.1.2 ! root 48: static __inline__ int issrc (tree t) 1.1 root 49: { 1.1.1.2 ! root 50: return t == tree_a || t == tree_b || t == tree_c || t == tree_d || t == tree_e || t == tree_f; 1.1 root 51: } 52: 53: static tree new_op_tree(enum tree_op op, tree l, tree r) 54: { 55: tree t; 56: if (op == op_not && l->op == op_not) { 57: t = l->left; 58: xfree(l); 59: return t; 60: } 61: t = (tree)xmalloc(sizeof(struct tree_n)); 62: t->left = l; 63: t->right = r; 64: t->op = op; 65: return t; 66: } 67: 1.1.1.2 ! root 68: static int opidx (tree t) 1.1 root 69: { 1.1.1.2 ! root 70: switch (t->op) { 1.1 root 71: case op_a: 1.1.1.2 ! root 72: return 0; 1.1 root 73: case op_b: 1.1.1.2 ! root 74: return 1; 1.1 root 75: case op_c: 1.1.1.2 ! root 76: return 2; ! 77: case op_d: ! 78: return 3; ! 79: case op_e: ! 80: return 4; ! 81: case op_f: ! 82: return 5; ! 83: default: ! 84: return -1; ! 85: } ! 86: } ! 87: ! 88: static int tree_cst (tree t, unsigned int *src, unsigned int *notsrc) ! 89: { ! 90: int idx = opidx (t); ! 91: if (idx >= 0) { ! 92: src[idx] = 1; 1.1 root 93: return 0; 1.1.1.2 ! root 94: } ! 95: switch (t->op) { 1.1 root 96: case op_not: 1.1.1.2 ! root 97: idx = opidx (t->left); ! 98: if (idx >= 0) { ! 99: notsrc[idx] = 1; ! 100: return 3; 1.1 root 101: } 1.1.1.2 ! root 102: return 3 + tree_cst (t->left, src, notsrc); 1.1 root 103: 104: case op_and: 105: case op_xor: 106: case op_or: 1.1.1.2 ! root 107: return 4 + tree_cst (t->left, src, notsrc) + tree_cst (t->right, src, notsrc); 1.1 root 108: 1.1.1.2 ! root 109: default: ! 110: abort (); 1.1 root 111: } 112: } 113: 1.1.1.2 ! root 114: static int tree_cost (tree t) 1.1 root 115: { 1.1.1.2 ! root 116: int i, cost; ! 117: unsigned int src[6], notsrc[6]; ! 118: memset (src, 0, sizeof src); ! 119: memset (notsrc, 0, sizeof notsrc); 1.1 root 120: 1.1.1.2 ! root 121: cost = tree_cst (t, src, notsrc); ! 122: for (i = 0; i < 6; i++) ! 123: if (src[i] && notsrc[i]) ! 124: cost++; ! 125: return cost; 1.1 root 126: } 127: 1.1.1.2 ! root 128: static int add_vec(tree_vec *tv, tree t) 1.1 root 129: { 1.1.1.2 ! root 130: int i; ! 131: #if 0 ! 132: if (! tree_isnormal(t)) 1.1 root 133: nop(2); 1.1.1.2 ! root 134: #endif ! 135: if (tv->ntrees == tv->space) { ! 136: tv->trees = (tree *)xrealloc(tv->trees, sizeof(tree)*(tv->space += 40)); 1.1 root 137: } 1.1.1.2 ! root 138: tv->trees[tv->ntrees++] = t; 1.1 root 139: 1.1.1.2 ! root 140: return 1; 1.1 root 141: } 142: 143: static void init_vec(tree_vec *tv) 144: { 145: tv->ntrees = tv->space = 0; 146: tv->trees = NULL; 147: } 148: 1.1.1.2 ! root 149: static void do_sprint_tree (char *s, tree t) 1.1 root 150: { 1.1.1.2 ! root 151: enum tree_op op = t->op; ! 152: switch (op) { 1.1 root 153: case op_a: 1.1.1.2 ! root 154: strcat (s, "srca"); 1.1 root 155: break; 156: case op_b: 1.1.1.2 ! root 157: strcat (s, "srcb"); 1.1 root 158: break; 159: case op_c: 1.1.1.2 ! root 160: strcat (s, "srcc"); 1.1 root 161: break; 1.1.1.2 ! root 162: case op_d: ! 163: strcat (s, "srcd"); 1.1 root 164: break; 1.1.1.2 ! root 165: case op_e: ! 166: strcat (s, "srce"); 1.1 root 167: break; 1.1.1.2 ! root 168: case op_f: ! 169: strcat (s, "srcf"); ! 170: break; ! 171: ! 172: case op_and: ! 173: case op_or: 1.1 root 174: case op_xor: 1.1.1.2 ! root 175: { ! 176: ! 177: char *c = op == op_and ? " & " : op == op_or ? " | " : " ^ "; ! 178: strcat (s, "("); ! 179: do_sprint_tree (s, t->left); ! 180: strcat (s, c); ! 181: while (t->right->op == op) { ! 182: t = t->right; ! 183: do_sprint_tree (s, t->left); ! 184: strcat (s, c); ! 185: } ! 186: do_sprint_tree(s, t->right); ! 187: strcat (s, ")"); 1.1 root 188: } 189: break; 1.1.1.2 ! root 190: 1.1 root 191: case op_not: 1.1.1.2 ! root 192: strcat (s, "~"); ! 193: do_sprint_tree (s, t->left); 1.1 root 194: break; 195: } 196: } 197: 1.1.1.2 ! root 198: static tree_vec size_trees[20]; 1.1 root 199: 1.1.1.2 ! root 200: static struct tree_n bad_tree = { op_and, &bad_tree, &bad_tree }; 1.1 root 201: 1.1.1.2 ! root 202: static unsigned int used_mask[256]; ! 203: static tree best_trees[256]; ! 204: static unsigned int best_cost[256]; ! 205: static int n_unknown; 1.1 root 206: 1.1.1.2 ! root 207: static unsigned long which_fn (tree t) 1.1 root 208: { 1.1.1.2 ! root 209: switch (t->op) { ! 210: case op_a: ! 211: return 0xf0; ! 212: case op_b: ! 213: return 0xcc; ! 214: case op_c: ! 215: return 0xaa; ! 216: case op_and: ! 217: return which_fn (t->left) & which_fn (t->right); ! 218: case op_or: ! 219: return which_fn (t->left) | which_fn (t->right); ! 220: case op_xor: ! 221: return which_fn (t->left) ^ which_fn (t->right); ! 222: case op_not: ! 223: return 0xFF & ~which_fn (t->left); ! 224: default: ! 225: abort (); 1.1 root 226: } 227: } 228: 1.1.1.2 ! root 229: static unsigned long tree_used_mask (tree t) 1.1 root 230: { 1.1.1.2 ! root 231: switch (t->op) { ! 232: case op_a: ! 233: return 1; ! 234: case op_b: ! 235: return 2; ! 236: case op_c: ! 237: return 4; ! 238: case op_and: ! 239: case op_or: ! 240: case op_xor: ! 241: return tree_used_mask (t->left) | tree_used_mask (t->right); ! 242: case op_not: ! 243: return tree_used_mask (t->left); ! 244: default: ! 245: abort (); 1.1 root 246: } 247: } 248: 1.1.1.2 ! root 249: static void candidate (tree_vec *v, tree t) 1.1 root 250: { 1.1.1.2 ! root 251: unsigned long fn = which_fn (t); ! 252: unsigned int cost = tree_cost (t); ! 253: if (best_trees[fn] == 0) ! 254: n_unknown--; ! 255: if (cost < best_cost[fn]) ! 256: best_trees[fn] = t, best_cost[fn] = cost; ! 257: add_vec (v, t); 1.1 root 258: } 259: 1.1.1.2 ! root 260: static void cand_and_not (tree_vec *v, tree t) 1.1 root 261: { 1.1.1.2 ! root 262: candidate (v, t); ! 263: t = new_op_tree (op_not, t, 0); ! 264: candidate (v, t); 1.1 root 265: } 266: 1.1.1.2 ! root 267: static void try_tree (tree_vec *v, tree t) 1.1 root 268: { 1.1.1.2 ! root 269: int fnl = which_fn (t->left); ! 270: int fnr = which_fn (t->right); ! 271: int fn = which_fn (t); ! 272: if (fn == fnl ! 273: || fn == fnr ! 274: || fn == 0 ! 275: || fn == 0xFF ! 276: || (tree_used_mask (t) & ~used_mask[fn]) != 0 ! 277: || best_cost[fn] + 6 < tree_cost (t)) ! 278: { ! 279: xfree (t); 1.1 root 280: return; 281: } 1.1.1.2 ! root 282: cand_and_not (v, t); 1.1 root 283: } 284: 1.1.1.2 ! root 285: static void find_best_trees (void) 1.1 root 286: { 1.1.1.2 ! root 287: int i, size, do_stop; ! 288: for (i = 0; i < 256; i++) { ! 289: best_trees[i] = i == 0 || i == 255 ? &bad_tree : 0; ! 290: best_cost[i] = 65535; ! 291: } ! 292: n_unknown = 254; ! 293: ! 294: init_vec (size_trees); ! 295: cand_and_not (size_trees, tree_a); ! 296: cand_and_not (size_trees, tree_b); ! 297: cand_and_not (size_trees, tree_c); ! 298: ! 299: do_stop = 0; ! 300: for (size = 2; ! do_stop && size < 20; size++) { ! 301: int split, last_split; ! 302: tree_vec *sv = size_trees + size - 1; ! 303: ! 304: if (n_unknown == 0) ! 305: do_stop = 1; ! 306: last_split = (size >> 1) + 1; ! 307: for (split = 1; split < last_split; split++) { ! 308: int szl = split; ! 309: int szr = size - split; ! 310: tree_vec *lv = size_trees + szl - 1; ! 311: tree_vec *rv = size_trees + szr - 1; ! 312: int i; 1.1 root 313: 1.1.1.2 ! root 314: for (i = 0; i < lv->ntrees; i++) { ! 315: tree l = lv->trees[i]; ! 316: int j; ! 317: for (j = szl == szr ? i + 1 : 0; j < rv->ntrees; j++) { ! 318: tree r = rv->trees[j]; ! 319: ! 320: if (l->op != op_and || r->op != op_and) { ! 321: tree tmp = (l->op == op_and ! 322: ? new_op_tree (op_and, r, l) ! 323: : new_op_tree (op_and, l, r)); ! 324: try_tree (sv, tmp); ! 325: } ! 326: if (l->op != op_or || r->op != op_or) { ! 327: tree tmp = (l->op == op_or ! 328: ? new_op_tree (op_or, r, l) ! 329: : new_op_tree (op_or, l, r)); ! 330: try_tree (sv, tmp); ! 331: } ! 332: if (l->op != op_xor || r->op != op_xor) { ! 333: tree tmp = (l->op == op_xor ! 334: ? new_op_tree (op_xor, r, l) ! 335: : new_op_tree (op_xor, l, r)); ! 336: try_tree (sv, tmp); ! 337: } ! 338: } ! 339: } 1.1 root 340: } 1.1.1.2 ! root 341: /* An additional pass doesn't seem to create better solutions ! 342: * (not that much of a surprise). */ ! 343: if (n_unknown == 0) ! 344: do_stop = 1; 1.1 root 345: } 346: } 347: 1.1.1.2 ! root 348: static int bitset (int mt, int bit) 1.1 root 349: { 350: return mt & (1 << bit); 351: } 352: 1.1.1.2 ! root 353: static unsigned int generate_expr (int minterm) 1.1 root 354: { 355: int bits = 0; 356: int i; 1.1.1.2 ! root 357: int expr_dc[8], nexp = 0; 1.1 root 358: int expr_used[8]; 359: 1.1.1.2 ! root 360: if (minterm == 0 || minterm == 0xFF) 1.1 root 361: return 0; 1.1.1.2 ! root 362: ! 363: for (i = 0; i < 8; i++) { ! 364: if (bitset (minterm, i) && !bitset (bits, i)) { 1.1 root 365: int j; 366: int dontcare = 0; 367: int firstand = 1; 368: int bitbucket[8], bitcount; 1.1.1.2 ! root 369: 1.1 root 370: bits |= 1<<i; 1.1.1.2 ! root 371: bitcount = 1; bitbucket[0] = i; 1.1 root 372: for(j=1; j<8; j *= 2) { 373: int success = 1; 374: int k; 1.1.1.2 ! root 375: for(k=0; k < bitcount; k++) { ! 376: if (!bitset (minterm, bitbucket[k] ^ j)) { 1.1 root 377: success = 0; 378: } 379: } 380: if (success) { 381: int l; 382: dontcare |= j; 383: for(l=bitcount; l < bitcount*2; l++) { 384: bitbucket[l] = bitbucket[l-bitcount] ^ j; 385: bits |= 1 << bitbucket[l]; 386: } 387: bitcount *= 2; 388: } 389: } 390: expr_used[nexp] = 1; 391: expr_dc[nexp] = dontcare; 1.1.1.2 ! root 392: nexp++; 1.1 root 393: } 394: } 1.1.1.2 ! root 395: ! 396: { ! 397: unsigned int result = 0; ! 398: for (i = 0; i < nexp; i++) { ! 399: int j; ! 400: ! 401: for (j = 1; j < 8; j *= 2) { ! 402: if (!(expr_dc[i] & j)) ! 403: result |= (j == 1 ? 4 : j == 2 ? 2 : 1); 1.1 root 404: } 405: } 1.1.1.2 ! root 406: return result; 1.1 root 407: } 408: } 409: 410: static void print_tree(tree t) 411: { 1.1.1.2 ! root 412: char buf[300] = ""; ! 413: do_sprint_tree (buf, t); ! 414: printf ("%s", buf); 1.1 root 415: } 416: 417: static void generate_optable(void) 418: { 419: int minterm; 420: printf(" /* This file generated automatically - do not edit */\n\n"); 421: printf("#include \"genblitter.h\"\n\n"); 422: printf("struct blitop blitops[256] = {\n"); 423: for (minterm = 0; minterm < 256; minterm++) { 424: printf(" /* %02x */ { \"", minterm); 1.1.1.2 ! root 425: if (minterm == 0) ! 426: printf ("0"); ! 427: else if (minterm == 255) ! 428: printf ("0xFFFFFFFF"); ! 429: else ! 430: print_tree (best_trees[minterm]); ! 431: ! 432: printf("\", %d }%s\n", used_mask[minterm], minterm == 255 ? "" : ","); 1.1 root 433: fflush(stdout); 434: } 435: printf("};\n"); 436: } 437: 1.1.1.2 ! root 438: int main (int argc, char **argv) 1.1 root 439: { 1.1.1.2 ! root 440: int minterm; ! 441: for (minterm = 0; minterm < 256; minterm++) ! 442: used_mask[minterm] = generate_expr (minterm); ! 443: find_best_trees (); ! 444: generate_optable (); 1.1 root 445: 446: return 0; 447: } 448: 1.1.1.2 ! root 449: void nop(int a) ! 450: { ! 451: } ! 452:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.