#include "common.h" #include "defopcode.h" #include "error.h" #include "bitstring.h" #include "generatecode.h" #include "byteorder.h" #include "reduce.h" #include "syn68k_private.h" #include "uniquestring.h" #include "safe_alloca.h" #include #include #include /* Global variables for this file. */ static OpcodeMappingInfo opcode_map_info[65536]; static const char *map_info_opcode_name[65536]; static uint16 map_index[65536]; static unsigned char synthetic_opcode_taken[65536]; /* Not booleans. */ static int num_map_infos; static int parity; /* Private helper functions. */ static void compute_optimal_shifts (const ParsedOpcodeInfo *info, int *shift, List *isect_list, int literal_bits, int literal_bits_mask); static void compute_literal_bits (const char *pattern, int *lbp, int *lbmp); static int compute_dashmask (const char *pattern); static int compute_synthetic_opcode (int m68k_opcode, const OpcodeMappingInfo *map); static void reserve_synthetic_ops (OpcodeMappingInfo *maps, int num_variants, int variant, int num_variant_mapping_sets, List *isect_list, int literal_bits, int literal_bits_mask); static BOOL has_unexpanded_register_lvalue (List *code, const char *opcode_bits, const char *bits_to_expand, int *index); static void delete_field (List *code, int field_number, int val); static void replace_dollar_number_with_list (List *code, int field, List *list); #define NO_MAP 0 #define OPCODE_TAKEN 0xFF #define OPCODE_NOT_TAKEN 0xFE #define SYNTHETIC_OPCODE_TAKEN(op, variant) \ (synthetic_opcode_taken[(op) & 0xFFFF] != OPCODE_NOT_TAKEN \ && synthetic_opcode_taken[(op) & 0xFFFF] != (variant)) /* Call this once before calling generate_opcode () for the first time. * Call done_generating_code () after you have called generate_opcode () for * the last time. */ void begin_generating_code () { int i; /* Clear mapping table to NO_MAP. */ for (i = 0; i < 65536; i++) map_index[i] = NO_MAP; for (i = 0; i < 65536; i++) synthetic_opcode_taken[i] = OPCODE_NOT_TAKEN; /* Zero the other arrays. */ memset (opcode_map_info, 0, sizeof opcode_map_info); memset (map_info_opcode_name, 0, sizeof map_info_opcode_name); /* Set up default "no mapping" map; maps to opcode 0. */ opcode_map_info[NO_MAP].cc_needed = M68K_CC_ALL; opcode_map_info[NO_MAP].sequence_parity = 0; opcode_map_info[NO_MAP].instruction_words = 1; opcode_map_info[NO_MAP].ends_block = TRUE; opcode_map_info[NO_MAP].next_block_dynamic = TRUE; map_info_opcode_name[0] = "(reserved)"; /* Opcodes 0 through 0xB4 are reserved. */ for (i = 0; i <= 0xB4; i++) synthetic_opcode_taken[i] = OPCODE_TAKEN; /* We've used one opcode map, and should now be on odd parity for the * next block of opcode maps. */ num_map_infos = 1; parity = 1; if (!preprocess_only) { FILE *fp = fopen ("syn68k_header.c", "r"); char buf[1024]; size_t size; if (fp == NULL) fatal_error ("Unable to open syn68k_header.c for reading!\n"); /* Copy the C preamble out to syn68k.c. */ while ((size = fread (buf, 1, 1024, fp)) != 0) fwrite (buf, 1, size, syn68k_c_stream); fclose (fp); } } /* Call this after you have called generate_opcode () for the last time. */ void done_generating_code () { if (!preprocess_only) { long i, max_opcode = -1; /* Close up the main interpreter function. */ fputs ("\n" "#ifndef USE_DIRECT_DISPATCH\n" " }\n" " }\n" "}\n" "#else\n" "/* This function is the gateway to the threaded code.\n" " * It allocates a bunch of space on the stack so that\n" " * (hopefully) there will be room for the stack slots in\n" " * the functions it jumps into. This is scary stuff,\n" " * but hopefully it will work. We put this function at\n" " * the end of the file so it won't be inlined.\n" " * And use __attribute__((noinline)) where it's supported.\n" " */\n" "static void\n" "threaded_gateway (void)\n" "{\n" "volatile char buf[1024]; /* Allocate some stack space. */\n" "memset ((char *)buf, 0, 1); /* Use the buffer in some way. */\n" "NEXT_INSTRUCTION (ROUND_UP (PTR_WORDS));\n" "}\n" "\n" "\n" "/* This array is used only by the compilation system. */\n", syn68k_c_stream); /* Output the decls for the dispatch table array. */ for (i = 0; i < 65536; i++) { if (synthetic_opcode_taken[i] == OPCODE_TAKEN) { fprintf (syn68k_c_stream, "extern int handle_opc_0x%04lX " "asm (\"_S68K_HANDLE_0x%04lX\");\n", (unsigned long) i, (unsigned long) i); max_opcode = i; } } /* Output the beginning of the dispatch table array. */ if (max_opcode >= 0) { fprintf (syn68k_c_stream, "\n" "\n" "const void *direct_dispatch_table[%ld] = {\n", max_opcode + 1); for (i = 0; i <= max_opcode; i++) { if (synthetic_opcode_taken[i] == OPCODE_TAKEN) fprintf (syn68k_c_stream, " (void *) &handle_opc_0x%04lX%s\n", (unsigned long) i, (i == max_opcode) ? "" : ","); else fprintf (syn68k_c_stream, " (void *) 0%s\n", (i == max_opcode) ? "" : ","); } fputs ("};\n", syn68k_c_stream); } fputs ("#endif /* USE_DIRECT_DISPATCH */\n", syn68k_c_stream); /* Output opcode map. */ if (verbose) printf ("Outputting opcode map index table..."), fflush (stdout); /* Output preamble for mapindex_c_stream. */ fputs ("#include \"syn68k_private.h\"\n" "\n" "const uint16 opcode_map_index[65536] = {\n" , mapindex_c_stream); /* Print out all of the values w/big endian indices. */ for (i = 0; i < 65536; i++) { unsigned ix = map_index[i]; if (ix == 0) /* Iff no map computed, make it behave */ ix = map_index[0x4AFC]; /* like ILLEGAL. */ fprintf (mapindex_c_stream, "%s0x%04X,", ((i % 8) == 0) ? " " : "", ix); if ((i % 8) == 7) fprintf (mapindex_c_stream, " /* 0x%04X */\n", (unsigned) i - 7); else putc (' ', mapindex_c_stream); } /* Output postamble for map index. */ fputs ("};\n", mapindex_c_stream); if (verbose) puts ("done."); /* Output map info. */ if (verbose) printf ("Outputting opcode map information table..."), fflush (stdout); /* Add a dummy entry at the end with a different parity so the last * map info sequence will be terminated. */ opcode_map_info[num_map_infos].sequence_parity = parity; map_info_opcode_name[num_map_infos] = "Internal use: array terminator"; num_map_infos++; /* Output preamble for mapinfo_c_stream. */ fprintf (mapinfo_c_stream, "#include \"syn68k_private.h\"\n" "#ifdef GENERATE_NATIVE_CODE\n" "#include \"native.h\"\n" "#include \"native/i386/host-xlate.h\"\n" "#include \"native/i386/xlate-aux.h\"\n" "#endif\n" "\n" "const OpcodeMappingInfo opcode_map_info[%d] = {\n", num_map_infos); /* Print out all of the structs. */ for (i = 0; i < num_map_infos; i++) { const OpcodeMappingInfo *m = &opcode_map_info[i]; int j; /* Put blank line between distinct opcode sequences. */ if (i > 0 && strcmp (map_info_opcode_name[i], map_info_opcode_name[i - 1])) putc ('\n', mapinfo_c_stream); /* Output the struct. */ fprintf (mapinfo_c_stream, " /* 0x%04X: %s */\n" " { %d, 0x%02X, 0x%02X, 0x%02X, %d, %d, %d, %d, %d, " "%d, %d, %2d, 0x%04X, 0x%04X,\n", (unsigned) i, map_info_opcode_name[i], m->sequence_parity, (unsigned) m->cc_may_set, (unsigned) m->cc_may_not_set, (unsigned) m->cc_needed, m->instruction_words, m->ends_block, m->next_block_dynamic, m->amode_size, m->reversed_amode_size, m->amode_expanded, m->reversed_amode_expanded, m->opcode_shift_count, (unsigned) m->opcode_and_bits, (unsigned) m->opcode_add_bits); /* Output the bitfields. */ fputs (" { ", mapinfo_c_stream); for (j = 0; j < MAX_BITFIELDS; j++) { if (j != 0 && (j % 2) == 0) fputs ("\n ", mapinfo_c_stream); fprintf (mapinfo_c_stream, "{ %d, %d, %d, %d, %d, %d }%s", m->bitfield[j].rev_amode, m->bitfield[j].index, m->bitfield[j].length, m->bitfield[j].sign_extend, m->bitfield[j].make_native_endian, m->bitfield[j].words, (j == sizeof m->bitfield / sizeof m->bitfield[0] - 1) ? "" : ", "); } #ifdef GENERATE_NATIVE_CODE fprintf (mapinfo_c_stream, " },\n" " %s%s },\n", (m->guest_code_descriptor == NULL) ? "" : "&", ((m->guest_code_descriptor == NULL) ? "NULL" : m->guest_code_descriptor)); #else fputs (" } },\n", mapinfo_c_stream); #endif } /* Output postamble for map info. */ fputs ("};\n", mapinfo_c_stream); if (verbose) puts ("done."); } } void generate_opcode (ParsedOpcodeInfo *info, SymbolTable *sym) { #if !defined(__GNUC__) extern void *alloca(int); #endif OperandInfo *operand_info; OpcodeMappingInfo *base; OpcodeMappingInfo *mapping; int num_variants, i, m68kop; CCVariant *var, *v; int num_variant_mapping_sets = 0; List expand; List opcode_pattern = { /* &expand */ 0, NULL, { TOK_QUOTED_STRING, { 0 } /* info->opcode_bits */, "(internal: generate_opcode)", 0 } }; List isect = { /* &opcode_pattern */ 0, NULL, { TOK_INTERSECT, { "intersect" }, "(internal: generate_opcode)", 0 } }; List isect_list = { NULL, /* &isect */ 0, { TOK_LIST, { "[LIST]" }, "(internal: generate_opcode)", 0 } }; int *dashmask, *shift; int *amode_size, *reversed_amode_size; BOOL *amode_expanded, *reversed_amode_expanded; int literal_bits, literal_bits_mask; int *unexpanded_synthetic_opcode; List **add_to_code_token; const char **postcode; SAFE_DECL(); opcode_pattern.cdr = &expand; opcode_pattern.token.u.string = info->opcode_bits; isect.cdr = &opcode_pattern; isect_list.car = &isect; /* Provide feedback to the user. */ if (verbose) printf ("Processing \"%s\"...", info->name), fflush (stdout); /* Count the number of CC variants we have. */ for (num_variants = 0, var = info->cc_variant; var != NULL; var = var->next) num_variants++; #if 0 if (verbose) putchar ('\n'); printf ("Entering with bits = %s\n", info->opcode_bits); #endif /* If no variants (weird), don't do anything. */ if (num_variants == 0) { if (verbose) puts ("done."); return; } /* Add legal addressing modes to intersection. */ expand = *info->amode; expand.cdr = NULL; /* Compute those opcode bits which must be either 0 or 1, so we only * call is_member_of_set() when there is a chance a bit pattern could * match. Purely a speed heuristic. */ compute_literal_bits (info->opcode_bits, &literal_bits, &literal_bits_mask); /* If NO m68kops are legal, return. This is not just a heuristic; we * really don't want to process opcodes that are illegal for some reason. * It may still be the case that all of the legal m68kops for this set * have already been done. */ if (empty_set (&isect_list, literal_bits_mask, literal_bits)) { if (verbose) puts (""); return; } /* Allocate space for unexpanded_synthetic_opcode. This helps us * share code for unexpanded cc variants. */ unexpanded_synthetic_opcode = (int *) malloc (65536 * num_variants * sizeof (int)); /* Compute optimal shift counts for different CC variants. */ shift = (int *) SAFE_alloca (num_variants * sizeof (int)); compute_optimal_shifts (info, shift, &isect_list, literal_bits, literal_bits_mask); /* Compute the dashmasks for each CC variant. */ dashmask = (int *) SAFE_alloca (num_variants * sizeof (int)); for (i = 0, var = info->cc_variant; var != NULL; i++, var = var->next) dashmask[i] = compute_dashmask (var->bits_to_expand); /* Detect the presence of amodes and reversed amodes. */ amode_size = (int *) SAFE_alloca (num_variants * sizeof (int)); reversed_amode_size = (int *) SAFE_alloca (num_variants * sizeof (int)); for (i = 0, var = info->cc_variant; var != NULL; i++, var = var->next) { Token *t = has_token_of_type (var->code, TOK_DOLLAR_AMODE); if (t == NULL) t = has_token_of_type (var->code, TOK_DOLLAR_AMODE_PTR); amode_size[i] = (t == NULL) ? 0 : t->u.dollarinfo.size; t = has_token_of_type (var->code, TOK_DOLLAR_REVERSED_AMODE); if (t == NULL) t = has_token_of_type (var->code, TOK_DOLLAR_REVERSED_AMODE_PTR); reversed_amode_size[i] = (t == NULL) ? 0 : t->u.dollarinfo.size; } /* Determine whether or not the amode/reversed amodes are expanded. */ amode_expanded = (BOOL *) SAFE_alloca (num_variants * sizeof (BOOL)); reversed_amode_expanded = (BOOL *) SAFE_alloca (num_variants * sizeof (BOOL)); for (i = 0, var = info->cc_variant; var != NULL; i++, var = var->next) { amode_expanded[i] = ((dashmask[i] & 0x3F) == 0x00); reversed_amode_expanded[i] = (((dashmask[i] >> 6) & 0x3F) == 0x00); } /* For unexpanded opcodes, this table tells to which synthetic opcode we * should map. Taking the m68kop & dashmask will give you an index * into this table; if the number at that table is not -1, it represents * the synthetic opcode to which you should map. If it is -1, then no * such synthetic opcode has yet been created and it should be created. */ memset (unexpanded_synthetic_opcode, -1, num_variants * 65536 * sizeof (int)); postcode = (const char **) SAFE_alloca (num_variants * sizeof (char *)); for (i = 0; i < num_variants; i++) postcode[i] = unique_string (""); /* Make sure that all register rvalues hidden in unexpanded * addressing modes get extracted and treated as unexpanded registers. * We will do this by creating an artificial, expanded 68k opcode entry, * processing it, and then continuing on to process this opcode normally. */ for (i = 0, v = info->cc_variant; v != NULL; i++, v = v->next) { BOOL changed = FALSE; List **original_var_code = (List **) SAFE_alloca (num_variants * sizeof (List *)); char **original_bits_to_expand = (char **) SAFE_alloca (num_variants * sizeof (const char *)); char original_opcode_bits[16 * MAX_OPCODE_WORDS]; BOOL old_verbose = verbose; int j; /* Save original opcode bits. */ strcpy (original_opcode_bits, info->opcode_bits); /* Save original code + bits_to_expand. */ for (j = 0, var = info->cc_variant; var != NULL; j++, var = var->next) { assert (j < num_variants); original_bits_to_expand[j] = var->bits_to_expand; original_var_code[j] = var->code; } /* Do we have an addressing mode? If so, split up the cases where the * addressing mode refers to a register (modes 0 and 1) and the cases * where it refers to memory (modes 2 through 7). If we create a * register lvalue, that will be caught on recursion below. * * NOTE: We used to only do this for unexpanded addressing modes, but * it turns out this doesn't work because we need to separate the reg * cases right away so we know whether or not to swap them. */ if (amode_size[i] != 0 /* && !amode_expanded[i] NO GOOD; see NOTE. */ && has_token_of_type (v->code, TOK_DOLLAR_AMODE)) { int mind = 10; TokenType replace = TOK_DOLLAR_AMODE; #ifndef M68K_REGS_IN_ARRAY /* Data register version. */ strncpy (info->opcode_bits + mind, "000", 3); for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { assert (j < num_variants); var->code = copy_list (original_var_code[j]); replace_tokens_of_type (var->code, replace, TOK_DOLLAR_DATA_REGISTER); } /* Generate code for the data register version. */ verbose = FALSE; #ifdef SPLIT_WARNING if (v->native_code_info != NULL) parse_error (v->code, "Splitting up insn with native code assist; " "this will scramble around your operands and cause " "other confusion. To fix this, make your case with " "the native code assist more specific.\n"); #endif generate_opcode (info, sym); /* Address register version. */ info->opcode_bits[mind + 2] = '1'; for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { var->code = copy_list (original_var_code[j]); replace_tokens_of_type (var->code, replace, TOK_DOLLAR_ADDRESS_REGISTER); } /* Generate code for the address register version. */ #ifdef SPLIT_WARNING if (v->native_code_info != NULL) parse_error (v->code, "Splitting up insn with native code assist; " "this will scramble around your operands and cause " "other confusion. To fix this, make your case with " "the native code assist more specific.\n"); #endif generate_opcode (info, sym); #else strncpy (info->opcode_bits + mind, "00", 2); for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { assert (j < num_variants); var->code = copy_list (original_var_code[j]); replace_tokens_of_type (var->code, replace, TOK_DOLLAR_GENERAL_REGISTER); } /* Generate code for the data/address register version. */ verbose = FALSE; #ifdef SPLIT_WARNING if (v->native_code_info != NULL) parse_error (v->code, "Splitting up insn with native code assist; " "this will scramble around your operands and cause " "other confusion. To fix this, make your case with " "the native code assist more specific.\n"); #endif generate_opcode (info, sym); #endif changed = TRUE; } /* If we changed anything, don't loop any more. */ if (changed) { /* Restore original opcode bits. */ strcpy (info->opcode_bits, original_opcode_bits); /* Restore original code + bits_to_expand. */ for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { assert (j < num_variants); var->bits_to_expand = original_bits_to_expand[j]; var->code = original_var_code[j]; } verbose = old_verbose; /* All done. */ break; } ASSERT_SAFE(original_var_code); ASSERT_SAFE(original_bits_to_expand); } /* Make sure that all register rvalues hidden in unexpanded * addressing modes get extracted and treated as unexpanded registers. * We will do this by creating an artificial, expanded 68k opcode entry, * processing it, and then continuing on to process this opcode normally. */ for (i = 0, v = info->cc_variant; v != NULL; i++, v = v->next) { BOOL changed = FALSE; List **original_var_code = (List **) SAFE_alloca (num_variants * sizeof (List *)); char **original_bits_to_expand = (char **) SAFE_alloca (num_variants * sizeof (const char *)); char original_opcode_bits[16 * MAX_OPCODE_WORDS]; BOOL old_verbose = verbose; int j; /* Save original opcode bits. */ strcpy (original_opcode_bits, info->opcode_bits); /* Save original code + bits_to_expand. */ for (j = 0, var = info->cc_variant; var != NULL; j++, var = var->next) { original_bits_to_expand[j] = var->bits_to_expand; original_var_code[j] = var->code; } /* Do we have a reversed addressing mode? If so, split up the * cases where the addressing mode refers to a register (modes 0 and 1) * and the cases where it refers to memory (modes 2 through 7). If * we create a register lvalue, that will be caught on recursion below. * * NOTE: We used to only do this for unexpanded addressing modes, but * it turns out this doesn't work because we need to separate the reg * cases right away so we know whether or not to swap them. */ if (reversed_amode_size[i] != 0 /* && !reversed_amode_expanded[i] */ && has_token_of_type (v->code, TOK_DOLLAR_REVERSED_AMODE)) { int mind = 7; TokenType replace = TOK_DOLLAR_REVERSED_AMODE; /* Data register version. */ strncpy (info->opcode_bits + mind, "000", 3); for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { var->code = copy_list (original_var_code[j]); replace_tokens_of_type (var->code, replace, TOK_DOLLAR_DATA_REGISTER); } /* Generate code for the data register version. */ verbose = FALSE; #ifdef SPLIT_WARNING if (v->native_code_info != NULL) parse_error (v->code, "Splitting up insn with native code assist; " "this will scramble around your operands and cause " "other confusion. To fix this, make your case with " "the native code assist more specific.\n"); #endif generate_opcode (info, sym); /* Address register version. */ info->opcode_bits[mind + 2] = '1'; for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { var->code = copy_list (original_var_code[j]); replace_tokens_of_type (var->code, replace, TOK_DOLLAR_ADDRESS_REGISTER); } /* Generate code for the address register version. */ #ifdef SPLIT_WARNING if (v->native_code_info != NULL) parse_error (v->code, "Splitting up insn with native code assist; " "this will scramble around your operands and cause " "other confusion. To fix this, make your case with " "the native code assist more specific.\n"); #endif generate_opcode (info, sym); changed = TRUE; } /* If we changed anything, don't loop any more. */ if (changed) { /* Restore original opcode bits. */ strcpy (info->opcode_bits, original_opcode_bits); /* Restore original code + bits_to_expand. */ for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { var->bits_to_expand = original_bits_to_expand[j]; var->code = original_var_code[j]; } verbose = old_verbose; /* All done. */ break; } ASSERT_SAFE(original_var_code); ASSERT_SAFE(original_bits_to_expand); } /* See if we need to split this opcode up and recurse because we * have an expanded addressing mode (or reversed addressing mode) * 111/000 [(xxx).W], 111/001 [(xxx).L], 101/xxx [(d16,An)] */ for (i = 0, v = info->cc_variant; v != NULL; i++, v = v->next) { BOOL changed = FALSE; List **original_var_code = (List **) SAFE_alloca (num_variants * sizeof (List *)); char **original_bits_to_expand = (char **) SAFE_alloca (num_variants * sizeof (const char *)); char original_opcode_bits[16 * MAX_OPCODE_WORDS + 1]; BOOL old_verbose = verbose; int j; /* Save original opcode bits. */ strcpy (original_opcode_bits, info->opcode_bits); /* Save original code + bits_to_expand. */ for (j = 0, var = info->cc_variant; var != NULL; j++, var = var->next) { original_bits_to_expand[j] = var->bits_to_expand; original_var_code[j] = var->code; } if (amode_size[i] != 0 && amode_expanded[i]) { int mind, rind, shr; TokenType replace; Token t; List ll, ld, ln; replace = TOK_DOLLAR_AMODE; mind = 10; rind = 13; shr = 0; t = *has_token_of_type (v->code, replace); /* Create top level list. */ ll.cdr = NULL; ll.car = &ld; ll.token.type = TOK_LIST; ll.token.u.string = "[LIST]"; ll.token.filename = "internal:defopcode.c"; ll.token.lineno = 0; /* Create deref. */ ld.cdr = &ln; ld.car = NULL; ld.token.type = TOK_DEREF; ld.token.u.derefinfo.size = t.u.dollarinfo.size; ld.token.u.derefinfo.sgnd = t.u.dollarinfo.sgnd; /* Create address to be deref'd. */ ln.cdr = NULL; ln.car = NULL; ln.token.type = TOK_DOLLAR_NUMBER; ln.token.u.dollarinfo.sgnd = TRUE; ln.token.u.dollarinfo.size = 4; ln.token.u.dollarinfo.which = num_fields (original_opcode_bits) + 1; propagate_fileinfo (&ll.token, &ll); /* (xxx).W */ strncpy (info->opcode_bits + mind, "111", 3); strncpy (info->opcode_bits + rind, "000", 3); make_unique_field_of_width (info->opcode_bits, info->opcode_bits + strlen (info->opcode_bits), 16); /* Loop over all variants and change amode ref to addr ref. */ for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { var->code = copy_list (original_var_code[j]); replace_tokens_of_type_with_list (var->code, replace, &ll); delete_field (var->code, field_with_index (original_opcode_bits, MIN (rind, mind)), (7 << (13 - mind)) >> shr); } /* Turn off verbose mode & generate code. */ verbose = FALSE; #ifdef SPLIT_WARNING if (v->native_code_info != NULL) parse_error (v->code, "Splitting up insn with native code assist; " "this will scramble around your operands and cause " "other confusion. To fix this, make your case with " "the native code assist more specific.\n"); #endif generate_opcode (info, sym); /* (xxx).L */ strncpy (info->opcode_bits + mind, "111", 3); strncpy (info->opcode_bits + rind, "001", 3); info->opcode_bits[strlen (original_opcode_bits)] = '\0'; make_unique_field_of_width (info->opcode_bits, info->opcode_bits + strlen (info->opcode_bits), 32); /* Loop over all variants and change amode ref to addr ref. */ for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { var->code = copy_list (original_var_code[j]); replace_tokens_of_type_with_list (var->code, replace, &ll); delete_field (var->code, field_with_index (original_opcode_bits, MIN (rind, mind)), ((1 << (13 - rind)) | (7 << (13 - mind))) >> shr); } /* Generate code. */ #ifdef SPLIT_WARNING if (v->native_code_info != NULL) parse_error (v->code, "Splitting up insn with native code assist; " "this will scramble around your operands and cause " "other confusion. To fix this, make your case with " "the native code assist more specific.\n"); #endif generate_opcode (info, sym); /* (d16,An) */ { char buf[256], buf2[256]; List *ls, *ls2; /* Must replace all $n.mxx with (derefxx (+ $n.aul $x.sl)) and * replace all $n.xx with * ([((5 << (13 - mind - shr)) + ($n.ul << (13 - rind - shr)))]) */ strcpy (info->opcode_bits, original_opcode_bits); strncpy (info->opcode_bits + mind, "101", 3); make_unique_field_of_width (info->opcode_bits, info->opcode_bits + strlen (info->opcode_bits), 16); sprintf (buf, "(deref%c%c (+ $%d.aul $%d.sl))", t.u.dollarinfo.sgnd ? 's' : 'u', " bw l"[t.u.dollarinfo.size], t.u.dollarinfo.which, num_fields (info->opcode_bits)); ls = string_to_list (buf, NULL); if (13 - rind - shr == 0) sprintf (buf2, "(+ %d $%d.ul)", 5 << (13 - mind - shr), t.u.dollarinfo.which); else sprintf (buf2, "(+ %d (<< $%d.ul %d))", 5 << (13 - mind - shr), t.u.dollarinfo.which, 13 - rind - shr); ls2 = string_to_list (buf2, NULL); /* Loop over all variants and change amode ref to addr ref. */ for (j = 0, var = info->cc_variant; var != NULL; j++, var = var->next) { var->code = copy_list (original_var_code[j]); replace_dollar_number_with_list (var->code, t.u.dollarinfo.which, ls2); replace_tokens_of_type_with_list (var->code, replace, ls); } } /* Generate code. */ #ifdef SPLIT_WARNING if (v->native_code_info != NULL) parse_error (v->code, "Splitting up insn with native code assist; " "this will scramble around your operands and cause " "other confusion. To fix this, make your case with " "the native code assist more specific.\n"); #endif generate_opcode (info, sym); changed = TRUE; } /* If we changed anything, don't loop any more. */ if (changed) { /* Restore original opcode bits. */ strcpy (info->opcode_bits, original_opcode_bits); /* Restore original code + bits_to_expand. */ for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { var->bits_to_expand = original_bits_to_expand[j]; var->code = original_var_code[j]; } verbose = old_verbose; /* All done. */ break; } ASSERT_SAFE(original_var_code); ASSERT_SAFE(original_bits_to_expand); } /* See if we need to split this opcode up and recurse because we * have an expanded addressing mode (or reversed addressing mode) * 111/000 [(xxx).W], 111/001 [(xxx).L], 101/xxx [(d16,An)] */ for (i = 0, v = info->cc_variant; v != NULL; i++, v = v->next) { BOOL changed = FALSE; List **original_var_code = (List **) SAFE_alloca (num_variants * sizeof (List *)); char **original_bits_to_expand = (char **) SAFE_alloca (num_variants * sizeof (const char *)); char original_opcode_bits[16 * MAX_OPCODE_WORDS + 1]; BOOL old_verbose = verbose; int j; /* Save original opcode bits. */ strcpy (original_opcode_bits, info->opcode_bits); /* Save original code + bits_to_expand. */ for (j = 0, var = info->cc_variant; var != NULL; j++, var = var->next) { original_bits_to_expand[j] = var->bits_to_expand; original_var_code[j] = var->code; } if (reversed_amode_size[i] != 0 && reversed_amode_expanded[i]) { int mind, rind, shr; TokenType replace; Token t; List ll, ld, ln; replace = TOK_DOLLAR_REVERSED_AMODE; mind = 7; rind = 4; shr = 6; t = *has_token_of_type (v->code, replace); /* Create top level list. */ ll.cdr = NULL; ll.car = &ld; ll.token.type = TOK_LIST; ll.token.u.string = "[LIST]"; ll.token.filename = "internal:defopcode.c"; ll.token.lineno = 0; /* Create deref. */ ld.cdr = &ln; ld.car = NULL; ld.token.type = TOK_DEREF; ld.token.u.derefinfo.size = t.u.dollarinfo.size; ld.token.u.derefinfo.sgnd = t.u.dollarinfo.sgnd; /* Create address to be deref'd. */ ln.cdr = NULL; ln.car = NULL; ln.token.type = TOK_DOLLAR_NUMBER; ln.token.u.dollarinfo.sgnd = TRUE; ln.token.u.dollarinfo.size = 4; ln.token.u.dollarinfo.which = num_fields (original_opcode_bits) + 1; propagate_fileinfo (&ll.token, &ll); /* (xxx).W */ strncpy (info->opcode_bits + mind, "111", 3); strncpy (info->opcode_bits + rind, "000", 3); make_unique_field_of_width (info->opcode_bits, info->opcode_bits + strlen (info->opcode_bits), 16); /* Loop over all variants and change amode ref to addr ref. */ for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { var->code = copy_list (original_var_code[j]); replace_tokens_of_type_with_list (var->code, replace, &ll); delete_field (var->code, field_with_index (original_opcode_bits, MIN (rind, mind)), (7 << (13 - mind)) >> shr); } /* Turn off verbose mode & generate code. */ verbose = FALSE; #ifdef SPLIT_WARNING if (v->native_code_info != NULL) parse_error (v->code, "Splitting up insn with native code assist; " "this will scramble around your operands and cause " "other confusion. To fix this, make your case with " "the native code assist more specific.\n"); #endif generate_opcode (info, sym); /* (xxx).L */ strncpy (info->opcode_bits + mind, "111", 3); strncpy (info->opcode_bits + rind, "001", 3); info->opcode_bits[strlen (original_opcode_bits)] = '\0'; make_unique_field_of_width (info->opcode_bits, info->opcode_bits + strlen (info->opcode_bits), 32); /* Loop over all variants and change amode ref to addr ref. */ for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { var->code = copy_list (original_var_code[j]); replace_tokens_of_type_with_list (var->code, replace, &ll); delete_field (var->code, field_with_index (original_opcode_bits, MIN (rind, mind)), ((1 << (13 - rind)) | (7 << (13 - mind))) >> shr); } /* Generate code. */ #ifdef SPLIT_WARNING if (v->native_code_info != NULL) parse_error (v->code, "Splitting up insn with native code assist; " "this will scramble around your operands and cause " "other confusion. To fix this, make your case with " "the native code assist more specific.\n"); #endif generate_opcode (info, sym); /* (d16,An) */ { char buf[256], buf2[256]; List *ls, *ls2; /* Must replace all $n.mxx with (derefxx (+ $n.aul $x.sl)) and * replace all $n.xx with * ([((5 << (13 - mind - shr)) + ($n.ul << (13 - rind - shr)))]) */ strcpy (info->opcode_bits, original_opcode_bits); strncpy (info->opcode_bits + mind, "101", 3); make_unique_field_of_width (info->opcode_bits, info->opcode_bits + strlen (info->opcode_bits), 16); sprintf (buf, "(deref%c%c (+ $%d.aul $%d.sl))", t.u.dollarinfo.sgnd ? 's' : 'u', " bw l"[t.u.dollarinfo.size], t.u.dollarinfo.which, num_fields (info->opcode_bits)); ls = string_to_list (buf, NULL); if (13 - rind - shr == 0) sprintf (buf2, "(+ %d $%d.ul)", 5 << (13 - mind - shr), t.u.dollarinfo.which); else sprintf (buf2, "(+ %d (<< $%d.ul %d))", 5 << (13 - mind - shr), t.u.dollarinfo.which, 13 - rind - shr); ls2 = string_to_list (buf2, NULL); /* Loop over all variants and change amode ref to addr ref. */ for (j = 0, var = info->cc_variant; var != NULL; j++, var = var->next) { var->code = copy_list (original_var_code[j]); replace_dollar_number_with_list (var->code, t.u.dollarinfo.which, ls2); replace_tokens_of_type_with_list (var->code, replace, ls); } } /* Generate code. */ #ifdef SPLIT_WARNING if (v->native_code_info != NULL) parse_error (v->code, "Splitting up insn with native code assist; " "this will scramble around your operands and cause " "other confusion. To fix this, make your case with " "the native code assist more specific.\n"); #endif generate_opcode (info, sym); changed = TRUE; } /* If we changed anything, don't loop any more. */ if (changed) { /* Restore original opcode bits. */ strcpy (info->opcode_bits, original_opcode_bits); /* Restore original code + bits_to_expand. */ for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { var->bits_to_expand = original_bits_to_expand[j]; var->code = original_var_code[j]; } verbose = old_verbose; /* All done. */ break; } ASSERT_SAFE(original_var_code); ASSERT_SAFE(original_bits_to_expand); } /* Expand out any #data addressing modes by creating a new opcode table * entry that explicitly mentions the operand and then recursing to * generate it. */ for (i = 0, v = info->cc_variant; v != NULL; i++, v = v->next) { BOOL changed = FALSE; List **original_var_code = (List **) SAFE_alloca (num_variants * sizeof (List *)); char **original_bits_to_expand = (char **) SAFE_alloca (num_variants * sizeof (const char *)); char original_opcode_bits[16 * MAX_OPCODE_WORDS + 1]; BOOL old_verbose = verbose; int j; /* Save original opcode bits. */ strcpy (original_opcode_bits, info->opcode_bits); /* Save original code + bits_to_expand. */ for (j = 0, var = info->cc_variant; var != NULL; j++, var = var->next) { original_bits_to_expand[j] = var->bits_to_expand; original_var_code[j] = var->code; } if (amode_size[i] != 0 || reversed_amode_size[i] != 0) { int mind, rind, shr; TokenType replace; Token t, *tp; List ln; if (amode_size[i] != 0) { replace = TOK_DOLLAR_AMODE; mind = 10; rind = 13; shr = 0; } else { replace = TOK_DOLLAR_REVERSED_AMODE; mind = 7; rind = 4; shr = 6; } tp = has_token_of_type (v->code, replace); if (tp != NULL) { t = *tp; /* # */ /* Set up ln. */ ln.token.type = TOK_DOLLAR_NUMBER; ln.token.u.dollarinfo.size = t.u.dollarinfo.size; ln.token.u.dollarinfo.sgnd = t.u.dollarinfo.sgnd; ln.token.u.dollarinfo.which = num_fields (info->opcode_bits) + 1; ln.token.filename = "Internal/defopcode.c"; ln.token.lineno = 0; ln.car = ln.cdr = NULL; strncpy (info->opcode_bits + mind, "111", 3); strncpy (info->opcode_bits + rind, "100", 3); if (t.u.dollarinfo.size == 1) strcat (info->opcode_bits, "00000000"); make_unique_field_of_width (info->opcode_bits, info->opcode_bits + strlen (info->opcode_bits), t.u.dollarinfo.size * 8); /* Loop over all variants and change amode ref to operand. */ for (j = 0, var = info->cc_variant; var != NULL; j++, var = var->next) { var->code = copy_list (original_var_code[j]); replace_tokens_of_type_with_list (var->code, replace, &ln); delete_field (var->code, field_with_index (original_opcode_bits, MIN (rind, mind)), ((4 << (13 - rind)) | (7 << (13 - mind))) >> shr); } /* Generate code. */ verbose = FALSE; #ifdef SPLIT_WARNING if (v->native_code_info != NULL) parse_error (v->code, "Splitting up insn with native code assist; " "this will scramble around your operands and cause " "other confusion. To fix this, make your case with " "the native code assist more specific.\n"); #endif generate_opcode (info, sym); changed = TRUE; } } /* If we changed anything, don't loop any more. */ if (changed) { /* Restore original opcode bits. */ strcpy (info->opcode_bits, original_opcode_bits); /* Restore original code + bits_to_expand. */ for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { var->bits_to_expand = original_bits_to_expand[j]; var->code = original_var_code[j]; } verbose = old_verbose; /* All done. */ break; } ASSERT_SAFE(original_var_code); ASSERT_SAFE(original_bits_to_expand); } #ifndef M68K_REGS_IN_ARRAY /* See if we need to split this opcode up and recurse because we have * an unexpanded register as an lvalue. */ for (i = 0, v = info->cc_variant; v != NULL; i++, v = v->next) { BOOL changed = FALSE; List **original_var_code = (List **) SAFE_alloca (num_variants * sizeof (List *)); char **original_bits_to_expand = (char **) SAFE_alloca (num_variants * sizeof (const char *)); char original_opcode_bits[16 * MAX_OPCODE_WORDS]; BOOL old_verbose = verbose; int index; int j; /* Save original opcode bits. */ strcpy (original_opcode_bits, info->opcode_bits); /* Save original code + bits_to_expand. */ for (j = 0, var = info->cc_variant; var != NULL; j++, var = var->next) { original_bits_to_expand[j] = var->bits_to_expand; original_var_code[j] = var->code; } /* Do we have an unexpanded register as an lvalue? If so, we need * to expand this register so we can have a legal lvalue and recurse. */ if (has_unexpanded_register_lvalue (v->code, info->opcode_bits, v->bits_to_expand, &index)) { char *new_bits_to_expand = (char *) SAFE_alloca (17 * num_variants); for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { strcpy (&new_bits_to_expand[j * 17], var->bits_to_expand); new_bits_to_expand[j * 17 + index] = new_bits_to_expand[j * 17 + index + 1] = new_bits_to_expand[j * 17 + index + 2] = 'x'; var->bits_to_expand = &new_bits_to_expand[j * 17]; var->code = copy_list (original_var_code[j]); } /* Turn off verbose mode; looks weird if you leave it on. */ verbose = FALSE; #ifdef SPLIT_WARNING if (v->native_code_info != NULL) parse_error (v->code, "Splitting up insn with native code assist; " "this will scramble around your operands and cause " "other confusion. To fix this, make your case with " "the native code assist more specific.\n"); #endif generate_opcode (info, sym); changed = TRUE; ASSERT_SAFE(new_bits_to_expand); } /* If we changed anything, don't loop any more. */ if (changed) { /* Restore original opcode bits. */ strcpy (info->opcode_bits, original_opcode_bits); /* Restore original code + bits_to_expand. */ for (j = 0, var = info->cc_variant; var != NULL; j++,var = var->next) { var->bits_to_expand = original_bits_to_expand[j]; var->code = original_var_code[j]; } verbose = old_verbose; /* All done. */ break; } ASSERT_SAFE(original_var_code); ASSERT_SAFE(original_bits_to_expand); } #endif /* Allocate array for ptrs to scheme code value to add to code. */ add_to_code_token = (List **) SAFE_alloca (num_variants * sizeof (List *)); for (i = 0; i < num_variants; i++) add_to_code_token[i] = NULL; /* Insert postambles to handle unexpanded predec/postinc's. */ for (i = 0, v = info->cc_variant; v != NULL; i++, v = v->next) { char buf[2048]; Token *ta, *tr; List *ls; /* Handle predecrement for unexpanded addressing modes by explicitly * checking for a predecrement mode and decrementing the pointer * if we find it. FIXME - this will perform the check even if * predec/postinc are not legal expansions! */ if (!info->dont_postincdec_unexpanded && !reversed_amode_expanded[i] && (tr = has_token_of_type (v->code, TOK_DOLLAR_REVERSED_AMODE))) { int s = tr->u.dollarinfo.size; /* Create a list describing the special stuff we want to do. * Here we are relying on the fact that the bit pattern for * the reversed addressing mode was already swapped to be * a non-reversed addressing mode. This should happen at * translation time. */ sprintf (buf, "(list " "\"\\n#ifdef M68K_REGS_IN_ARRAY\\n\" " "(call \"CLEANUP_AMODE\" $%d.ul %d) " "\"\\n#else\\n\" " "(switch $%d.ul (0x18 (assign a0.ul (+ a0.ul %d)))" "(0x19 (assign a1.ul (+ a1.ul %d)))" "(0x1A (assign a2.ul (+ a2.ul %d)))" "(0x1B (assign a3.ul (+ a3.ul %d)))" "(0x1C (assign a4.ul (+ a4.ul %d)))" "(0x1D (assign a5.ul (+ a5.ul %d)))" "(0x1E (assign a6.ul (+ a6.ul %d)))" "(0x1F (assign a7.ul (+ a7.ul %d)))" "(0x20 (assign a0.ul (- a0.ul %d)))" "(0x21 (assign a1.ul (- a1.ul %d)))" "(0x22 (assign a2.ul (- a2.ul %d)))" "(0x23 (assign a3.ul (- a3.ul %d)))" "(0x24 (assign a4.ul (- a4.ul %d)))" "(0x25 (assign a5.ul (- a5.ul %d)))" "(0x26 (assign a6.ul (- a6.ul %d)))" "(0x27 (assign a7.ul (- a7.ul %d)))) " "\"\\n#endif\\n\"" ")", tr->u.dollarinfo.which, s, tr->u.dollarinfo.which, s, s, s, s, s, s, s, (s == 1) ? 2 : s, s, s, s, s, s, s, s, (s == 1) ? 2 : s); /* Insert this code into original code. */ ls = string_to_list (buf, NULL); v->code->cdr = CDAR (ls); CDAR (ls) = v->code; v->code = ls; } if (!info->dont_postincdec_unexpanded && !amode_expanded[i] && (ta = has_token_of_type (v->code, TOK_DOLLAR_AMODE)) != NULL) { assert (ta->u.dollarinfo.size == 1 || ta->u.dollarinfo.size == 2 || ta->u.dollarinfo.size == 4); sprintf (buf, "(list " "\"\\n#ifdef M68K_REGS_IN_ARRAY\\n\" " " (call \"CLEANUP_AMODE\" $%d.ul %d) " "\"\\n#else\\n\"" " (assign \"amode\" $%d.ul) " " (assign code (+ code 666))" /* 666 repl. later. */ "\"\\n#endif\\n\" " ")", ta->u.dollarinfo.which, ta->u.dollarinfo.size, ta->u.dollarinfo.which); ls = string_to_list (buf, NULL); add_to_code_token[i] = CDDAR (CDDAR (CDR (CDDR (CDDAR (ls))))); v->code->cdr = CDAR (ls); CDAR (ls) = v->code; v->code = ls; sprintf (buf, "\n#ifndef M68K_REGS_IN_ARRAY\n" " CLEANUP_AMODE (amode, %d);\n" "#endif\n", ta->u.dollarinfo.size); postcode[i] = unique_string (buf); } } /* Insert byte swaps, compute bitfields for OpcodeMappingInfo, * and generate code to grab operands. */ operand_info = (OperandInfo *) SAFE_alloca (num_variants * sizeof (OperandInfo)); for (i = 0, v = info->cc_variant; v != NULL; i++, v = v->next) { int operands; operands = compute_operand_info (&operand_info[i], info, v); if (add_to_code_token[i] != NULL) add_to_code_token[i]->token.u.n = (!info->ends_block) ? operands : 0; } /* Grab a pointer to the first OpcodeMappingInfo struct in our set * of sequences. */ base = &opcode_map_info[num_map_infos]; /* Loop over all 64K possible opcodes and process those which match. */ for (m68kop = 0; m68kop < 65536; m68kop++) { int set; /* If this 68k opcode has already been done, or we shouldn't be * doing it, move on and try the next one. */ if ((m68kop & literal_bits_mask) != literal_bits || map_index[m68kop] != NO_MAP || !is_member_of_set (m68kop, &isect_list)) continue; /* See if one of the sets of opcode maps we've already made works. */ mapping = NULL; /* Default: no mapping set found. */ for (set = 0; set < num_variant_mapping_sets; set++) { for (i = 0; i < num_variants; i++) { int new; int maskedop = m68kop & ~(dashmask[i] & ~literal_bits_mask); new = compute_synthetic_opcode (m68kop, &base[set * num_variants + i]); /* If the computed synthetic opcode is taken, punt. Note that * it's OK for it to be taken if we are not fully expanding * and therefore we are sharing a synthetic opcode with * some other 68k opcode. */ if (unexpanded_synthetic_opcode[i * 65536 + maskedop] != -1) { if (new != unexpanded_synthetic_opcode[i * 65536 + maskedop]) break; } else if (SYNTHETIC_OPCODE_TAKEN (new, i)) break; } /* Did we find a match for all of the variants? */ if (i == num_variants) { mapping = &base[set * num_variants]; break; } } /* Did we fail to find a useful set of mappings? */ if (mapping == NULL) { /* Store the base of the new mapping set. */ mapping = &opcode_map_info[num_map_infos]; /* Create new mapping here. */ for (i = 0, var = info->cc_variant; var; i++, var = var->next) { OpcodeMappingInfo *m = &mapping[i]; int maskedop = m68kop & ~(dashmask[i] & ~literal_bits_mask); int add, n; /* Remember this opcode. */ map_info_opcode_name[num_map_infos + i] = info->name; /* Configure this opcode mapping. */ m->sequence_parity = parity; m->cc_may_set = var->cc_may_set; m->cc_may_not_set = var->cc_may_not_set; m->cc_needed = var->cc_needed; m->instruction_words = strlen (info->opcode_bits) / 16; m->ends_block = info->ends_block; m->next_block_dynamic = info->next_block_dynamic; m->opcode_shift_count = shift[i]; m->opcode_and_bits = ~(dashmask[i] | literal_bits_mask); m->opcode_add_bits = 0; /* Dummy; replaced below. */ m->amode_size = ((amode_size[i] == 4) ? 3 : amode_size[i]); m->reversed_amode_size = ((reversed_amode_size[i] == 4) ? 3 : reversed_amode_size[i]); m->amode_expanded = amode_expanded[i]; m->reversed_amode_expanded = reversed_amode_expanded[i]; /* Copy precomputed operand bitfield information. */ memcpy (m->bitfield, operand_info[i].bitfield, sizeof m->bitfield); if (operand_info[i].num_bitfields < MAX_BITFIELDS) { m->bitfield[operand_info[i].num_bitfields].index = MAGIC_END_INDEX; m->bitfield[operand_info[i].num_bitfields].length = MAGIC_END_LENGTH; } #ifdef GENERATE_NATIVE_CODE if (var->native_code_info == NULL) m->guest_code_descriptor = NULL; else m->guest_code_descriptor = var->native_code_info; #endif /* Find the add_bits that will map us to the smallest untaken * synthetic opcode, or to the smallest synthetic opcode * we are allowed to share because we aren't fully expanding. */ n = compute_synthetic_opcode (m68kop, m); if (unexpanded_synthetic_opcode[i * 65536 + maskedop] != -1) add = unexpanded_synthetic_opcode[i * 65536 + maskedop] - n; else { add = -n; while (SYNTHETIC_OPCODE_TAKEN (add + n, i)) add++; } m->opcode_add_bits = (add & 0xFFFF); /* Reserve all synthetic opcodes for this CC variant that * we can now attain, so that other CC variants don't choose * mappings that conflict. */ reserve_synthetic_ops (base, num_variants, i, num_variant_mapping_sets + 1, &isect_list, literal_bits, literal_bits_mask); } num_map_infos += num_variants; num_variant_mapping_sets++; parity = !parity; } /* Record the index to the correct mapping information. */ map_index[m68kop] = mapping - opcode_map_info; /* Output profiling info about this opcode; this information * will can be used by the profiler to group related bit patterns * together and determine how frequently different 68k instructions * are used. */ fprintf (profileinfo_stream, "%d %d %d %d %d %s\n", m68kop, amode_size[0] != 0, reversed_amode_size[0] != 0, literal_bits_mask, literal_bits, info->name); /* Loop over all of the CC variants, unreserve opcodes, and reserve * them again. This minimizes the number of synthetic ops reserved. * Why? Because two different OpcodeMappingInfo structs may map * a given CC variant to different synthetic opcodes for the same 68k * opcode. Since we don't know which OpcodeMappingInfo will be * chosen for that 68k opcode until we actually process it, we end * up reserving more opcodes than we actually need to (since some * of the reservations are mutually exclusive). Once we nail down * to where a 68k opcode maps, re-reserving everything will avoid * reserving any mutually exclusive reservations. */ #if 0 /* Doesn't help; increases OpcodeMappingInfo's more than * it decreases the # of synthetic opcodes. */ if (optimization_level > 0) for (i = 0; i < num_variants; i++) { unsigned char *p; int synop = compute_synthetic_opcode (m68kop, &mapping[i]); int j; /* Unreserve synthetic opcodes for this variant. */ for (p = synthetic_opcode_taken, j = 65535; j >= 0; p++, j--) if (*p == i) *p = OPCODE_NOT_TAKEN; /* Reserve the synthetic opcode we just made. */ if (synthetic_opcode_taken[synop] == OPCODE_NOT_TAKEN) synthetic_opcode_taken[synop] = i; /* Reserve synthetic opcodes for this variant. */ reserve_synthetic_ops (base, num_variants, i, num_variant_mapping_sets, &isect_list, literal_bits, literal_bits_mask); } #endif /* Loop over all of the CC variants & generate code. */ for (i = 0, var = info->cc_variant; var != NULL; i++, var = var->next) { int synop = compute_synthetic_opcode (m68kop, &mapping[i]); int maskedop = m68kop & ~(dashmask[i] & ~literal_bits_mask); /* If code has already been generated for this opcode, we must * be sharing code. No need to generate new code, so try next * variant. */ if (synthetic_opcode_taken[synop] == OPCODE_TAKEN) continue; /* Sanity check - verify that this synop was properly reserved. */ if (synthetic_opcode_taken[synop] == OPCODE_NOT_TAKEN) { error ("Internal error: generating code for unreserved synop " "0x%04X for m68kop\n ", (unsigned) synop); print_16_bits (stderr, m68kop); error (" (dashmask = "); print_16_bits (stderr, dashmask[i]); error (", shift = %d,\n add_bits = 0x%04X, " "and_bits = ", mapping[i].opcode_shift_count, mapping[i].opcode_add_bits); print_16_bits (stderr, mapping[i].opcode_and_bits); error (")"); error (" for variant %d.\n", i); } else if (synthetic_opcode_taken[synop] != i) { error ("Internal error generating code for synop 0x%04X for " "m68kop ", (unsigned) synop); print_16_bits (stderr, m68kop); error (" for variant %d; already reserved for variant %d!\n", i, synthetic_opcode_taken[synop]); } /* Remember the appropriate synthetic opcode for this guy * in case he isn't fully expanded; this way, other m68k * opcodes that should be mapped to the same handler will * know which synthetic opcode to use. */ unexpanded_synthetic_opcode[i * 65536 + maskedop] = compute_synthetic_opcode (m68kop, &mapping[i]); /* Lock down this synthetic opcode forever. */ synthetic_opcode_taken[synop] = OPCODE_TAKEN; /* Generate C code for this variant. */ generate_c_code (info, var, m68kop, synop, sym, operand_info[i].operand_decls, postcode[i], &mapping[i]); } } /* Unreserve all reserved (but not taken) opcodes, if any are left. */ for (i = 0; i < 65536; i++) if (synthetic_opcode_taken[i] != OPCODE_TAKEN && synthetic_opcode_taken[i] != OPCODE_NOT_TAKEN) { synthetic_opcode_taken[i] = OPCODE_NOT_TAKEN; } free (unexpanded_synthetic_opcode); ASSERT_SAFE(shift); ASSERT_SAFE(dashmask); ASSERT_SAFE(amode_size); ASSERT_SAFE(reversed_amode_size); ASSERT_SAFE(amode_expanded); ASSERT_SAFE(reversed_amode_expanded); ASSERT_SAFE(postcode); ASSERT_SAFE(add_to_code_token); ASSERT_SAFE(operand_info); if (verbose) puts ("done."); } int synthetic_opcode_size (const OpcodeMappingInfo *map) { int i, size = PTR_WORDS; /* Account for the synthetic opcode. */ for (i = 0; i < MAX_BITFIELDS; i++) { if (IS_TERMINATING_BITFIELD (&map->bitfield[i])) break; size += map->bitfield[i].words + 1; } return size; } /* For each cc variant, sees just how far it can shift the 68k pattern * to the right without losing any information it might need in the * translation to a synthetic opcode. If it can shift out all of the bits, * returns a shift count of 0. */ static void compute_optimal_shifts (const ParsedOpcodeInfo *info, int *shift, List *isect_list, int literal_bits, int literal_bits_mask) { int m68kop; BOOL first = TRUE; int i; const CCVariant *var; int known_pattern, changing_bits = 0; /* Determine which bits in the 68k opcode can take on different values. */ known_pattern = 0; for (m68kop = 0; m68kop < 65536; m68kop++) { if ((m68kop & literal_bits_mask) == literal_bits && map_index[m68kop] == NO_MAP && is_member_of_set (m68kop, isect_list)) { if (first) { known_pattern = m68kop; first = FALSE; } else changing_bits |= known_pattern ^ m68kop; } } /* Determine optimal shift count for each cc variant by locating the lowest * 68k opcode bit used in the 68k->synthetic translation which can take on * different values. */ for (i = 0, var = info->cc_variant; var != NULL; i++, var = var->next) { int cbits = changing_bits; /* Recommend we shift out all '-'s in the bits_to_expand. */ cbits &= ~compute_dashmask (var->bits_to_expand); /* Compute good shift count based on lowest changing bit. */ if (cbits == 0) /* If no bits change, don't bother shifting. */ shift[i] = 0; else /* Shift until lowest changing bit is in lsb position. */ for (shift[i] = 0; !((cbits >> shift[i]) & 1); shift[i]++) ; } } /* Given a string like "00001--0-----000", returns a bit mask containing a 1 in * each position where the original string contained a '-', and a 0 * everywhere else. */ static int compute_dashmask (const char *pattern) { int i, mask = 0, len = strlen (pattern); for (i = 0; i < len; i++) if (pattern[len - 1 - i] == '-') mask |= (1 << i); return mask; } /* Given a string like "00xx01x011dd1001", generates a mask for those bits * known to contain 0 or 1 values, and a list of those values. For example, * in the example the mask would be 1100110111001111 and the values would * be 0000010011001001 (unused values are set to 0). */ static void compute_literal_bits (const char *pattern, int *lbp, int *lbmp) { int i; int literal_bits = 0, literal_bits_mask = 0; for (i = 0; i < 16; i++) { if (pattern[15 - i] == '0') literal_bits_mask |= 1 << i; else if (pattern[15 - i] == '1') { literal_bits_mask |= 1 << i; literal_bits |= 1 << i; } } *lbp = literal_bits; *lbmp = literal_bits_mask; } static int compute_synthetic_opcode (int m68k_opcode, const OpcodeMappingInfo *map) { return (((m68k_opcode & map->opcode_and_bits) >> map->opcode_shift_count) + map->opcode_add_bits) & 0xFFFF; } /* This function "reserves" all synthetic opcodes that might be computed * during the mapping from 68k->synthetic opcodes for a particular variant. * This helps minimize the number of OpcodeMappingInfo sequences we'll need * by minimizing conflicts between different CC variants of the same opcode. */ static void reserve_synthetic_ops (OpcodeMappingInfo *maps, int num_variants, int variant, int num_variant_mapping_sets, List *isect_list, int literal_bits, int literal_bits_mask) { int m68kop; int i; for (m68kop = 0; m68kop < 65536; m68kop++) { if ((m68kop & literal_bits_mask) != literal_bits || map_index[m68kop] != NO_MAP || !is_member_of_set (m68kop, isect_list)) continue; for (i = 0; i < num_variant_mapping_sets; i++) { int synop = compute_synthetic_opcode (m68kop, &maps[num_variants * i + variant]); if (!SYNTHETIC_OPCODE_TAKEN (synop, variant)) synthetic_opcode_taken[synop] = variant; } } } static BOOL has_unexpanded_register_lvalue (List *code, const char *opcode_bits, const char *bits_to_expand, int *index) { if (code == NULL) return FALSE; if (code->token.type == TOK_ASSIGN && code->cdr != NULL && (code->cdr->token.type == TOK_DOLLAR_DATA_REGISTER || code->cdr->token.type == TOK_DOLLAR_ADDRESS_REGISTER)) { int field = code->cdr->token.u.dollarinfo.which; if (!field_expanded (field, opcode_bits, bits_to_expand)) { PatternRange range; pattern_range (opcode_bits, field, &range); if (range.index < 16) { /* Only report regs that we can possibly expand. */ *index = range.index; return TRUE; } } } /* Recurse on the rest of the list. */ return (has_unexpanded_register_lvalue (code->car, opcode_bits, bits_to_expand, index) || has_unexpanded_register_lvalue (code->cdr, opcode_bits, bits_to_expand, index)); } static void delete_field (List *code, int field_number, int val) { if (code == NULL) return; if (IS_DOLLAR_TOKEN (code->token.type)) { if (code->token.u.dollarinfo.which == field_number) { if (code->token.type != TOK_DOLLAR_NUMBER) parse_error (code, "Deleting field that still exists!\n"); else { code->token.type = TOK_NUMBER; code->token.u.n = val; } } else if (code->token.u.dollarinfo.which > field_number) --code->token.u.dollarinfo.which; } delete_field (code->car, field_number, val); delete_field (code->cdr, field_number, val); } static void replace_dollar_number_with_list (List *code, int field, List *list) { if (code == NULL) return; if (code->token.type == TOK_DOLLAR_NUMBER && code->token.u.dollarinfo.which == field) { List *new = copy_list (list); List *old_cdr = code->cdr; *code = *new; code->cdr = old_cdr; } else replace_dollar_number_with_list (code->car, field, list); replace_dollar_number_with_list (code->cdr, field, list); }