/* * UAE - The Un*x Amiga Emulator * * Optimized blitter minterm function generator * * Copyright 1995,1996 Bernd Schmidt * Copyright 1996 Alessandro Bissacco * * Overkill, n: cf. genblitter */ #include "sysconfig.h" #include "sysdeps.h" #include "options.h" static void nop(int); #define xmalloc malloc #define xfree free #define xrealloc realloc typedef struct tree_n { enum tree_op { op_and, op_or, op_xor, op_not, op_a, op_b, op_c, op_d, op_e, op_f } op; struct tree_n *left, *right; } *tree; static struct tree_n TRA = { op_a, NULL, NULL }; static struct tree_n TRB = { op_b, NULL, NULL }; static struct tree_n TRC = { op_c, NULL, NULL }; static struct tree_n TRD = { op_d, NULL, NULL }; static struct tree_n TRE = { op_e, NULL, NULL }; static struct tree_n TRF = { op_f, NULL, NULL }; static tree tree_a = &TRA; static tree tree_b = &TRB; static tree tree_c = &TRC; static tree tree_d = &TRD; static tree tree_e = &TRE; static tree tree_f = &TRF; typedef struct { tree *trees; int space; int ntrees; } tree_vec; STATIC_INLINE int issrc (tree t) { return t == tree_a || t == tree_b || t == tree_c || t == tree_d || t == tree_e || t == tree_f; } static tree new_op_tree(enum tree_op op, tree l, tree r) { tree t; if (op == op_not && l->op == op_not) { t = l->left; xfree(l); return t; } t = (tree)xmalloc(sizeof(struct tree_n)); t->left = l; t->right = r; t->op = op; return t; } static int opidx (tree t) { switch (t->op) { case op_a: return 0; case op_b: return 1; case op_c: return 2; case op_d: return 3; case op_e: return 4; case op_f: return 5; default: return -1; } } static int tree_cst (tree t, unsigned int *src, unsigned int *notsrc) { int idx = opidx (t); if (idx >= 0) { src[idx] = 1; return 0; } switch (t->op) { case op_not: idx = opidx (t->left); if (idx >= 0) { notsrc[idx] = 1; return 3; } return 3 + tree_cst (t->left, src, notsrc); case op_and: case op_xor: case op_or: return 4 + tree_cst (t->left, src, notsrc) + tree_cst (t->right, src, notsrc); default: abort (); } } static int tree_cost (tree t) { int i, cost; unsigned int src[6], notsrc[6]; memset (src, 0, sizeof src); memset (notsrc, 0, sizeof notsrc); cost = tree_cst (t, src, notsrc); for (i = 0; i < 6; i++) if (src[i] && notsrc[i]) cost++; return cost; } static int add_vec(tree_vec *tv, tree t) { int i; #if 0 if (! tree_isnormal(t)) nop(2); #endif if (tv->ntrees == tv->space) { tv->trees = (tree *)xrealloc(tv->trees, sizeof(tree)*(tv->space += 40)); } tv->trees[tv->ntrees++] = t; return 1; } static void init_vec(tree_vec *tv) { tv->ntrees = tv->space = 0; tv->trees = NULL; } static void do_sprint_tree (char *s, tree t) { enum tree_op op = t->op; switch (op) { case op_a: strcat (s, "srca"); break; case op_b: strcat (s, "srcb"); break; case op_c: strcat (s, "srcc"); break; case op_d: strcat (s, "srcd"); break; case op_e: strcat (s, "srce"); break; case op_f: strcat (s, "srcf"); break; case op_and: case op_or: case op_xor: { char *c = op == op_and ? " & " : op == op_or ? " | " : " ^ "; strcat (s, "("); do_sprint_tree (s, t->left); strcat (s, c); while (t->right->op == op) { t = t->right; do_sprint_tree (s, t->left); strcat (s, c); } do_sprint_tree(s, t->right); strcat (s, ")"); } break; case op_not: strcat (s, "~"); do_sprint_tree (s, t->left); break; } } static tree_vec size_trees[20]; static struct tree_n bad_tree = { op_and, &bad_tree, &bad_tree }; static unsigned int used_mask[256]; static tree best_trees[256]; static unsigned int best_cost[256]; static int n_unknown; static unsigned long which_fn (tree t) { switch (t->op) { case op_a: return 0xf0; case op_b: return 0xcc; case op_c: return 0xaa; case op_and: return which_fn (t->left) & which_fn (t->right); case op_or: return which_fn (t->left) | which_fn (t->right); case op_xor: return which_fn (t->left) ^ which_fn (t->right); case op_not: return 0xFF & ~which_fn (t->left); default: abort (); } } static unsigned long tree_used_mask (tree t) { switch (t->op) { case op_a: return 1; case op_b: return 2; case op_c: return 4; case op_and: case op_or: case op_xor: return tree_used_mask (t->left) | tree_used_mask (t->right); case op_not: return tree_used_mask (t->left); default: abort (); } } static void candidate (tree_vec *v, tree t) { unsigned long fn = which_fn (t); unsigned int cost = tree_cost (t); if (best_trees[fn] == 0) n_unknown--; if (cost < best_cost[fn]) best_trees[fn] = t, best_cost[fn] = cost; add_vec (v, t); } static void cand_and_not (tree_vec *v, tree t) { candidate (v, t); t = new_op_tree (op_not, t, 0); candidate (v, t); } static void try_tree (tree_vec *v, tree t) { int fnl = which_fn (t->left); int fnr = which_fn (t->right); int fn = which_fn (t); if (fn == fnl || fn == fnr || fn == 0 || fn == 0xFF || (tree_used_mask (t) & ~used_mask[fn]) != 0 || best_cost[fn] + 6 < tree_cost (t)) { xfree (t); return; } cand_and_not (v, t); } static void find_best_trees (void) { int i, size, do_stop; for (i = 0; i < 256; i++) { best_trees[i] = i == 0 || i == 255 ? &bad_tree : 0; best_cost[i] = 65535; } n_unknown = 254; init_vec (size_trees); cand_and_not (size_trees, tree_a); cand_and_not (size_trees, tree_b); cand_and_not (size_trees, tree_c); do_stop = 0; for (size = 2; ! do_stop && size < 20; size++) { int split, last_split; tree_vec *sv = size_trees + size - 1; if (n_unknown == 0) do_stop = 1; last_split = (size >> 1) + 1; for (split = 1; split < last_split; split++) { int szl = split; int szr = size - split; tree_vec *lv = size_trees + szl - 1; tree_vec *rv = size_trees + szr - 1; int i; for (i = 0; i < lv->ntrees; i++) { tree l = lv->trees[i]; int j; for (j = szl == szr ? i + 1 : 0; j < rv->ntrees; j++) { tree r = rv->trees[j]; if (l->op != op_and || r->op != op_and) { tree tmp = (l->op == op_and ? new_op_tree (op_and, r, l) : new_op_tree (op_and, l, r)); try_tree (sv, tmp); } if (l->op != op_or || r->op != op_or) { tree tmp = (l->op == op_or ? new_op_tree (op_or, r, l) : new_op_tree (op_or, l, r)); try_tree (sv, tmp); } if (l->op != op_xor || r->op != op_xor) { tree tmp = (l->op == op_xor ? new_op_tree (op_xor, r, l) : new_op_tree (op_xor, l, r)); try_tree (sv, tmp); } } } } /* An additional pass doesn't seem to create better solutions * (not that much of a surprise). */ if (n_unknown == 0) do_stop = 1; } } static int bitset (int mt, int bit) { return mt & (1 << bit); } static unsigned int generate_expr (int minterm) { int bits = 0; int i; int expr_dc[8], nexp = 0; int expr_used[8]; if (minterm == 0 || minterm == 0xFF) return 0; for (i = 0; i < 8; i++) { if (bitset (minterm, i) && !bitset (bits, i)) { int j; int dontcare = 0; int firstand = 1; int bitbucket[8], bitcount; bits |= 1<