#define INLINE
#endif
+/* Used by the ifield rtx function. */
+#define FLD(f) (fields->f)
+
static const char * insert_normal
- PARAMS ((CGEN_OPCODE_DESC, long, unsigned int, int, int, int,
- CGEN_INSN_BYTES_PTR));
+ PARAMS ((CGEN_OPCODE_DESC, long, unsigned int, unsigned int, unsigned int,
+ unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR));
static const char * parse_insn_normal
PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *,
const char **, CGEN_FIELDS *));
CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma));
\f
/* -- assembler routines inserted here */
+/* -- asm.c */
+/* Handle register lists for LDMx and STMx */
+
+static int
+parse_register_number (strp)
+ const char **strp;
+{
+ int regno;
+ if (**strp < '0' || **strp > '9')
+ return -1; /* error */
+ regno = **strp - '0';
+ ++*strp;
+
+ if (**strp >= '0' && **strp <= '9')
+ {
+ regno = regno * 10 + (**strp - '0');
+ ++*strp;
+ }
+
+ return regno;
+}
+
+static const char *
+parse_register_list (od, strp, opindex, valuep, high_low, load_store)
+ CGEN_OPCODE_DESC od;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+ int high_low; /* 0 == high, 1 == low */
+ int load_store; /* 0 == load, 1 == store */
+{
+ int regno;
+ *valuep = 0;
+ while (**strp && **strp != ')')
+ {
+ if (**strp != 'R' && **strp != 'r')
+ break;
+ ++*strp;
+
+ regno = parse_register_number (strp);
+ if (regno == -1)
+ return "Register number is not valid";
+ if (regno > 7 && !high_low)
+ return "Register must be between r0 and r7";
+ if (regno < 8 && high_low)
+ return "Register must be between r8 and r15";
+
+ if (high_low)
+ regno -= 8;
+
+ if (load_store) /* mask is reversed for store */
+ *valuep |= 0x80 >> regno;
+ else
+ *valuep |= 1 << regno;
+
+ if (**strp == ',')
+ {
+ if (*(*strp + 1) == ')')
+ break;
+ ++*strp;
+ }
+ }
+
+ if (!*strp || **strp != ')')
+ return "Register list is not valid";
+
+ return NULL;
+}
+
+static const char *
+parse_low_register_list_ld (od, strp, opindex, valuep)
+ CGEN_OPCODE_DESC od;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+{
+ return parse_register_list (od, strp, opindex, valuep, 0/*low*/, 0/*load*/);
+}
+
+static const char *
+parse_hi_register_list_ld (od, strp, opindex, valuep)
+ CGEN_OPCODE_DESC od;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+{
+ return parse_register_list (od, strp, opindex, valuep, 1/*high*/, 0/*load*/);
+}
+
+static const char *
+parse_low_register_list_st (od, strp, opindex, valuep)
+ CGEN_OPCODE_DESC od;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+{
+ return parse_register_list (od, strp, opindex, valuep, 0/*low*/, 1/*store*/);
+}
+
+static const char *
+parse_hi_register_list_st (od, strp, opindex, valuep)
+ CGEN_OPCODE_DESC od;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+{
+ return parse_register_list (od, strp, opindex, valuep, 1/*high*/, 1/*store*/);
+}
+
+/* -- */
/* Main entry point for operand parsing.
case FR30_OPERAND_RJ :
errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_gr, & fields->f_Rj);
break;
+ case FR30_OPERAND_RIC :
+ errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_gr, & fields->f_Ric);
+ break;
+ case FR30_OPERAND_RJC :
+ errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_gr, & fields->f_Rjc);
+ break;
+ case FR30_OPERAND_CRI :
+ errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_cr, & fields->f_CRi);
+ break;
+ case FR30_OPERAND_CRJ :
+ errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_cr, & fields->f_CRj);
+ break;
case FR30_OPERAND_RS1 :
errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_dr, & fields->f_Rs1);
break;
case FR30_OPERAND_RS2 :
errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_dr, & fields->f_Rs2);
break;
+ case FR30_OPERAND_R13 :
+ errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_r13, & fields->f_nil);
+ break;
+ case FR30_OPERAND_R14 :
+ errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_r14, & fields->f_nil);
+ break;
+ case FR30_OPERAND_R15 :
+ errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_r15, & fields->f_nil);
+ break;
+ case FR30_OPERAND_PS :
+ errmsg = cgen_parse_keyword (od, strp, & fr30_cgen_opval_h_ps, & fields->f_nil);
+ break;
case FR30_OPERAND_U4 :
errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_U4, &fields->f_u4);
break;
- case FR30_OPERAND_M4 :
- errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_M4, &fields->f_m4);
+ case FR30_OPERAND_U4C :
+ errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_U4C, &fields->f_u4c);
+ break;
+ case FR30_OPERAND_U8 :
+ errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_U8, &fields->f_u8);
break;
case FR30_OPERAND_I8 :
errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_I8, &fields->f_i8);
break;
- case FR30_OPERAND_U8 :
- errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_U8, &fields->f_u8);
+ case FR30_OPERAND_UDISP6 :
+ errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_UDISP6, &fields->f_udisp6);
+ break;
+ case FR30_OPERAND_DISP8 :
+ errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_DISP8, &fields->f_disp8);
break;
- case FR30_OPERAND_O8 :
- errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_O8, &fields->f_o8);
+ case FR30_OPERAND_DISP9 :
+ errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_DISP9, &fields->f_disp9);
+ break;
+ case FR30_OPERAND_DISP10 :
+ errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_DISP10, &fields->f_disp10);
break;
case FR30_OPERAND_S10 :
errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_S10, &fields->f_s10);
case FR30_OPERAND_U10 :
errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_U10, &fields->f_u10);
break;
+ case FR30_OPERAND_I32 :
+ errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_I32, &fields->f_i32);
+ break;
+ case FR30_OPERAND_M4 :
+ errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_M4, &fields->f_m4);
+ break;
+ case FR30_OPERAND_I20 :
+ errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_I20, &fields->f_i20);
+ break;
case FR30_OPERAND_DIR8 :
errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_DIR8, &fields->f_dir8);
break;
errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_DIR10, &fields->f_dir10);
break;
case FR30_OPERAND_LABEL9 :
- errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_LABEL9, &fields->f_rel8);
+ {
+ bfd_vma value;
+ errmsg = cgen_parse_address (od, strp, FR30_OPERAND_LABEL9, 0, NULL, & value);
+ fields->f_rel9 = value;
+ }
break;
case FR30_OPERAND_LABEL12 :
- errmsg = cgen_parse_signed_integer (od, strp, FR30_OPERAND_LABEL12, &fields->f_rel11);
+ {
+ bfd_vma value;
+ errmsg = cgen_parse_address (od, strp, FR30_OPERAND_LABEL12, 0, NULL, & value);
+ fields->f_rel12 = value;
+ }
+ break;
+ case FR30_OPERAND_REGLIST_LOW_LD :
+ errmsg = parse_low_register_list_ld (od, strp, FR30_OPERAND_REGLIST_LOW_LD, &fields->f_reglist_low_ld);
+ break;
+ case FR30_OPERAND_REGLIST_HI_LD :
+ errmsg = parse_hi_register_list_ld (od, strp, FR30_OPERAND_REGLIST_HI_LD, &fields->f_reglist_hi_ld);
+ break;
+ case FR30_OPERAND_REGLIST_LOW_ST :
+ errmsg = parse_low_register_list_st (od, strp, FR30_OPERAND_REGLIST_LOW_ST, &fields->f_reglist_low_st);
+ break;
+ case FR30_OPERAND_REGLIST_HI_ST :
+ errmsg = parse_hi_register_list_st (od, strp, FR30_OPERAND_REGLIST_HI_ST, &fields->f_reglist_hi_st);
break;
case FR30_OPERAND_CC :
errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_CC, &fields->f_cc);
break;
+ case FR30_OPERAND_CCC :
+ errmsg = cgen_parse_unsigned_integer (od, strp, FR30_OPERAND_CCC, &fields->f_ccc);
+ break;
default :
/* xgettext:c-format */
bfd_vma pc;
{
const char * errmsg;
+ unsigned int total_length = CGEN_FIELDS_BITSIZE (fields);
switch (opindex)
{
case FR30_OPERAND_RI :
- errmsg = insert_normal (od, fields->f_Ri, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, CGEN_FIELDS_BITSIZE (fields), buffer);
+ errmsg = insert_normal (od, fields->f_Ri, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 12, 4, 16, total_length, buffer);
break;
case FR30_OPERAND_RJ :
- errmsg = insert_normal (od, fields->f_Rj, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 4, CGEN_FIELDS_BITSIZE (fields), buffer);
+ errmsg = insert_normal (od, fields->f_Rj, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 4, 16, total_length, buffer);
+ break;
+ case FR30_OPERAND_RIC :
+ errmsg = insert_normal (od, fields->f_Ric, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 12, 4, 16, total_length, buffer);
+ break;
+ case FR30_OPERAND_RJC :
+ errmsg = insert_normal (od, fields->f_Rjc, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 8, 4, 16, total_length, buffer);
+ break;
+ case FR30_OPERAND_CRI :
+ errmsg = insert_normal (od, fields->f_CRi, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 12, 4, 16, total_length, buffer);
+ break;
+ case FR30_OPERAND_CRJ :
+ errmsg = insert_normal (od, fields->f_CRj, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 8, 4, 16, total_length, buffer);
break;
case FR30_OPERAND_RS1 :
- errmsg = insert_normal (od, fields->f_Rs1, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 4, CGEN_FIELDS_BITSIZE (fields), buffer);
+ errmsg = insert_normal (od, fields->f_Rs1, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 4, 16, total_length, buffer);
break;
case FR30_OPERAND_RS2 :
- errmsg = insert_normal (od, fields->f_Rs2, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, CGEN_FIELDS_BITSIZE (fields), buffer);
+ errmsg = insert_normal (od, fields->f_Rs2, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 12, 4, 16, total_length, buffer);
+ break;
+ case FR30_OPERAND_R13 :
+ errmsg = insert_normal (od, fields->f_nil, 0, 0, 0, 0, 0, total_length, buffer);
+ break;
+ case FR30_OPERAND_R14 :
+ errmsg = insert_normal (od, fields->f_nil, 0, 0, 0, 0, 0, total_length, buffer);
+ break;
+ case FR30_OPERAND_R15 :
+ errmsg = insert_normal (od, fields->f_nil, 0, 0, 0, 0, 0, total_length, buffer);
+ break;
+ case FR30_OPERAND_PS :
+ errmsg = insert_normal (od, fields->f_nil, 0, 0, 0, 0, 0, total_length, buffer);
break;
case FR30_OPERAND_U4 :
- errmsg = insert_normal (od, fields->f_u4, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 8, 4, CGEN_FIELDS_BITSIZE (fields), buffer);
+ errmsg = insert_normal (od, fields->f_u4, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 4, 16, total_length, buffer);
break;
- case FR30_OPERAND_M4 :
+ case FR30_OPERAND_U4C :
+ errmsg = insert_normal (od, fields->f_u4c, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 0, 12, 4, 16, total_length, buffer);
+ break;
+ case FR30_OPERAND_U8 :
+ errmsg = insert_normal (od, fields->f_u8, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
+ break;
+ case FR30_OPERAND_I8 :
+ errmsg = insert_normal (od, fields->f_i8, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 0, 4, 8, 16, total_length, buffer);
+ break;
+ case FR30_OPERAND_UDISP6 :
{
- long value = fields->f_m4;
- value = ((value) & (15));
- errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 8, 4, CGEN_FIELDS_BITSIZE (fields), buffer);
+ long value = fields->f_udisp6;
+ value = ((unsigned int) (value) >> (2));
+ errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 4, 16, total_length, buffer);
}
break;
- case FR30_OPERAND_I8 :
- errmsg = insert_normal (od, fields->f_i8, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 4, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+ case FR30_OPERAND_DISP8 :
+ errmsg = insert_normal (od, fields->f_disp8, 0|(1<<CGEN_OPERAND_HASH_PREFIX), 0, 4, 8, 16, total_length, buffer);
break;
- case FR30_OPERAND_U8 :
- errmsg = insert_normal (od, fields->f_u8, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+ case FR30_OPERAND_DISP9 :
+ {
+ long value = fields->f_disp9;
+ value = ((int) (value) >> (1));
+ errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX), 0, 4, 8, 16, total_length, buffer);
+ }
break;
- case FR30_OPERAND_O8 :
- errmsg = insert_normal (od, fields->f_o8, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 4, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+ case FR30_OPERAND_DISP10 :
+ {
+ long value = fields->f_disp10;
+ value = ((int) (value) >> (2));
+ errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX), 0, 4, 8, 16, total_length, buffer);
+ }
break;
case FR30_OPERAND_S10 :
{
long value = fields->f_s10;
- value = ((((unsigned int) (value) >> (2))) & (255));
- errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_SIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+ value = ((int) (value) >> (2));
+ errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX), 0, 8, 8, 16, total_length, buffer);
}
break;
case FR30_OPERAND_U10 :
{
long value = fields->f_u10;
- value = ((((unsigned int) (value) >> (2))) & (255));
- errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+ value = ((unsigned int) (value) >> (2));
+ errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
+ }
+ break;
+ case FR30_OPERAND_I32 :
+ errmsg = insert_normal (od, fields->f_i32, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_UNSIGNED), 16, 0, 32, 32, total_length, buffer);
+ break;
+ case FR30_OPERAND_M4 :
+ {
+ long value = fields->f_m4;
+ value = ((value) & (15));
+ errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 4, 16, total_length, buffer);
+ }
+ break;
+ case FR30_OPERAND_I20 :
+ {
+do {
+ FLD (f_i20_4) = ((unsigned int) (FLD (f_i20)) >> (16));
+ FLD (f_i20_16) = ((FLD (f_i20)) & (65535));
+} while (0);
+ errmsg = insert_normal (od, fields->f_i20_4, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED)|(1<<CGEN_OPERAND_VIRTUAL), 0, 8, 4, 16, total_length, buffer);
+ if (errmsg)
+ break;
+ errmsg = insert_normal (od, fields->f_i20_16, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED)|(1<<CGEN_OPERAND_VIRTUAL), 16, 0, 16, 16, total_length, buffer);
+ if (errmsg)
+ break;
}
break;
case FR30_OPERAND_DIR8 :
- errmsg = insert_normal (od, fields->f_dir8, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+ errmsg = insert_normal (od, fields->f_dir8, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
break;
case FR30_OPERAND_DIR9 :
{
long value = fields->f_dir9;
- value = ((((unsigned int) (value) >> (1))) & (255));
- errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+ value = ((unsigned int) (value) >> (1));
+ errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
}
break;
case FR30_OPERAND_DIR10 :
{
long value = fields->f_dir10;
- value = ((((unsigned int) (value) >> (2))) & (255));
- errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+ value = ((unsigned int) (value) >> (2));
+ errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
}
break;
case FR30_OPERAND_LABEL9 :
{
- long value = fields->f_rel8;
- value = ((((unsigned int) (value) >> (1))) & (255));
- errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_SIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), buffer);
+ long value = fields->f_rel9;
+ value = ((int) (((value) - (((pc) + (2))))) >> (1));
+ errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_PCREL_ADDR), 0, 8, 8, 16, total_length, buffer);
}
break;
case FR30_OPERAND_LABEL12 :
{
- long value = fields->f_rel11;
- value = ((((unsigned int) (value) >> (1))) & (2047));
- errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_SIGNED), 5, 11, CGEN_FIELDS_BITSIZE (fields), buffer);
+ long value = fields->f_rel12;
+ value = ((int) (((value) - (((pc) + (2))))) >> (1));
+ errmsg = insert_normal (od, value, 0|(1<<CGEN_OPERAND_PCREL_ADDR), 0, 5, 11, 16, total_length, buffer);
}
break;
+ case FR30_OPERAND_REGLIST_LOW_LD :
+ errmsg = insert_normal (od, fields->f_reglist_low_ld, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
+ break;
+ case FR30_OPERAND_REGLIST_HI_LD :
+ errmsg = insert_normal (od, fields->f_reglist_hi_ld, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
+ break;
+ case FR30_OPERAND_REGLIST_LOW_ST :
+ errmsg = insert_normal (od, fields->f_reglist_low_st, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
+ break;
+ case FR30_OPERAND_REGLIST_HI_ST :
+ errmsg = insert_normal (od, fields->f_reglist_hi_st, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 8, 16, total_length, buffer);
+ break;
case FR30_OPERAND_CC :
- errmsg = insert_normal (od, fields->f_cc, 0|(1<<CGEN_OPERAND_UNSIGNED), 4, 4, CGEN_FIELDS_BITSIZE (fields), buffer);
+ errmsg = insert_normal (od, fields->f_cc, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 4, 4, 16, total_length, buffer);
+ break;
+ case FR30_OPERAND_CCC :
+ errmsg = insert_normal (od, fields->f_ccc, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 16, 0, 8, 16, total_length, buffer);
break;
default :
/* ??? This may need reworking as these cases don't necessarily
want the first byte and the last two bytes handled like this. */
if (big_p)
- x = (bfd_getb8 (bufp) << 16) | bfd_getb16 (bufp + 1);
+ x = (bufp[0] << 16) | bfd_getb16 (bufp + 1);
else
- x = bfd_getl16 (bufp) | (bfd_getb8 (bufp + 2) << 16);
+ x = bfd_getl16 (bufp) | (bufp[2] << 16);
break;
case 32:
if (big_p)
/* Written this way to avoid undefined behaviour. */
mask = (((1L << (length - 1)) - 1) << 1) | 1;
if (CGEN_INSN_LSB0_P)
- shift = start;
+ shift = (start + 1) - length;
else
shift = (word_length - (start + length));
x = (x & ~(mask << shift)) | ((value & mask) << shift);
want the first byte and the last two bytes handled like this. */
if (big_p)
{
- bfd_putb8 (x >> 16, bufp);
+ bufp[0] = x >> 16;
bfd_putb16 (x, bufp + 1);
}
else
{
bfd_putl16 (x, bufp);
- bfd_putb8 (x >> 16, bufp + 2);
+ bufp[2] = x >> 16;
}
break;
case 32:
/* Default insertion routine.
ATTRS is a mask of the boolean attributes.
- START is the starting bit number, architecture origin.
+ WORD_OFFSET is the offset in bits from the start of the insn of the value.
+ WORD_LENGTH is the length of the word in bits in which the value resides.
+ START is the starting bit number in the word, architecture origin.
LENGTH is the length of VALUE in bits.
- TOTAL_LENGTH is the total length of the insn.
+ TOTAL_LENGTH is the total length of the insn in bits.
The result is an error message or NULL if success. */
-/* ??? May need to know word length in order to properly place values as
- an insn may be made of multiple words and the current bit number handling
- may be insufficient. Word length is an architectural attribute and thus
- methinks the way to go [if needed] is to fetch this value from OD or
- define a macro in <arch>-opc.h rather than adding an extra argument -
- after all that's how endianness is handled. */
/* ??? This duplicates functionality with bfd's howto table and
bfd_install_relocation. */
-/* ??? For architectures where insns can be representable as ints,
- store insn in `field' struct and add registers, etc. while parsing? */
/* ??? This doesn't handle bfd_vma's. Create another function when
necessary. */
static const char *
-insert_normal (od, value, attrs, start, length, total_length, buffer)
+insert_normal (od, value, attrs, word_offset, start, length, word_length,
+ total_length, buffer)
CGEN_OPCODE_DESC od;
long value;
unsigned int attrs;
- int start;
- int length;
- int total_length;
+ unsigned int word_offset, start, length, word_length, total_length;
CGEN_INSN_BYTES_PTR buffer;
{
static char errbuf[100];
if (length == 0)
return NULL;
+ if (CGEN_INT_INSN_P
+ && word_offset != 0)
+ abort ();
+
+ if (word_length > 32)
+ abort ();
+
+ /* For architectures with insns smaller than the insn-base-bitsize,
+ word_length may be too big. */
+#if CGEN_MIN_INSN_BITSIZE < CGEN_BASE_INSN_BITSIZE
+ if (word_offset == 0
+ && word_length > total_length)
+ word_length = total_length;
+#endif
+
/* Ensure VALUE will fit. */
- if ((attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED)) != 0)
+ if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
{
unsigned long maxval = mask;
if ((unsigned long) value > maxval)
#if CGEN_INT_INSN_P
- if (total_length > 32)
- abort ();
{
int shift;
if (CGEN_INSN_LSB0_P)
- shift = start;
+ shift = (start + 1) - length;
else
- shift = total_length - (start + length);
+ shift = word_length - (start + length);
*buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
}
-#else
-
- /* FIXME: unfinished and untested */
-
-/* ??? To be defined in <arch>-opc.h as necessary. */
-#ifndef CGEN_WORD_ENDIAN
-#define CGEN_WORD_ENDIAN(od) CGEN_OPCODE_ENDIAN (od)
-#endif
-#ifndef CGEN_INSN_WORD_ENDIAN
-#define CGEN_INSN_WORD_ENDIAN(od) CGEN_WORD_ENDIAN (od)
-#endif
-
- /* The hard case is probably too slow for the normal cases.
- It's certainly more difficult to understand than the normal case.
- Thus this is split into two. Keep it that way. The hard case is defined
- to be when a field straddles a (loosely defined) word boundary
- (??? which may require target specific help to determine). */
+#else /* ! CGEN_INT_INSN_P */
-#if 0 /*wip*/
-
-#define HARD_CASE_P 0 /* FIXME:wip */
-
- if (HARD_CASE_P)
- {
- unsigned char *bufp = (unsigned char *) buffer;
- int insn_length_left = total_length;
-
- if (CGEN_INSN_LSB0_P)
- {
- int word_offset = (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG
- ? ...
- : start / CGEN_BASE_INSN_BITSIZE);
- bufp += word_offset * (CGEN_BASE_INSN_BITSIZE / 8);
- if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
- else
- start -= word_offset * CGEN_BASE_INSN_BITSIZE;
- }
- else
- {
- int word_offset = (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG
- ? start / CGEN_BASE_INSN_BITSIZE
- : ...);
- bufp += word_offset * (CGEN_BASE_INSN_BITSIZE / 8);
- if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
- start -= word_offset * CGEN_BASE_INSN_BITSIZE;
- else
- }
-
- /* Loop so we handle a field straddling an insn word boundary
- (remember, "insn word boundary" is loosely defined here). */
-
- while (length > 0)
- {
- int this_pass_length = length;
- int this_pass_start = start;
- int this_pass_word_length = min (insn_length_left,
- (CGEN_BASE_INSN_BITSIZE == 8
- ? 32
- : CGEN_BASE_INSN_BITSIZE));
-
- insert_1 (od, value, attrs,
- this_pass_start, this_pass_length, this_pass_word_length,
- bufp);
-
- length -= this_pass_length;
- insn_length_left -= this_pass_word_length;
- if (???)
- {
- value >>= ???;
- start += ???;
- }
- else
- {
- value >>= ???;
- start += ???;
- }
- bufp += this_pass_word_length / 8;
- }
- }
- else
-#endif /* 0 */
- {
- unsigned char *bufp = (unsigned char *) buffer;
-
- if (length > 32)
- abort ();
-
- /* Adjust start,total_length,bufp to point to the pseudo-word that holds
- the value. For example in a 48 bit insn where the value to insert
- (say an immediate value) is the last 16 bits then word_length here
- would be 16. To handle a 24 bit insn with an 18 bit immediate,
- insert_1 handles 24 bits (using a combination of bfd_get8,16). */
-
- if (total_length > 32)
- {
- int needed_width = start % 8 + length;
- int fetch_length = (needed_width <= 8 ? 8
- : needed_width <= 16 ? 16
- : 32);
-
- if (CGEN_INSN_LSB0_P)
- {
- if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
- {
- abort (); /* wip */
- }
- else
- {
- int offset = start & ~7;
-
- bufp += offset / 8;
- start -= offset;
- total_length -= offset;
- }
- }
- else
- {
- if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
- {
- int offset = start & ~7;
-
- bufp += offset / 8;
- start -= offset;
- total_length -= offset;
- }
- else
- {
- abort (); /* wip */
- }
- }
- }
+ {
+ unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
- insert_1 (od, value, start, length, total_length, bufp);
- }
+ insert_1 (od, value, start, length, word_length, bufp);
+ }
#endif /* ! CGEN_INT_INSN_P */
const unsigned char * syn;
CGEN_INIT_INSERT (od);
- value = CGEN_INSN_VALUE (insn);
+ value = CGEN_INSN_BASE_VALUE (insn);
/* If we're recording insns as numbers (rather than a string of bytes),
target byte order handling is deferred until later. */
#else
- cgen_insn_put_value (od, buffer, min (CGEN_BASE_INSN_BITSIZE,
+ cgen_put_insn_value (od, buffer, min (CGEN_BASE_INSN_BITSIZE,
CGEN_FIELDS_BITSIZE (fields)),
value);
#endif /* ! CGEN_INT_INSN_P */
- /* ??? Rather than scanning the syntax string again, we could store
- in `fields' a null terminated list of the fields that are present. */
+ /* ??? It would be better to scan the format's fields.
+ Still need to be able to insert a value based on the operand though;
+ e.g. storing a branch displacement that got resolved later.
+ Needs more thought first. */
for (syn = CGEN_SYNTAX_STRING (syntax); * syn != '\0'; ++ syn)
{
str = start;
- /* Record a default length for the insn. This will get set to the
- correct value while parsing. */
- /* FIXME: wip */
+ /* Allow parse/insert handlers to obtain length of insn. */
CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
if (! CGEN_PARSE_FN (insn) (od, insn, & str, fields))