syn68k/syngen/defopcode.c
2008-09-26 08:25:10 -06:00

1885 lines
60 KiB
C

#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 <string.h>
#include <stdlib.h>
#include <assert.h>
/* 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 ("<subsumed!>");
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;
/* #<data> */
/* 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);
}