static unsigned int current_cpu = S390_OPCODE_MAXCPU - 1;
static unsigned int current_mode_mask = 0;
+/* Set to TRUE if the highgprs flag in the ELF header needs to be set
+ for the output file. */
+static bfd_boolean set_highgprs_p = FALSE;
+
/* Whether to use user friendly register names. Default is TRUE. */
#ifndef TARGET_REG_NAMES_P
#define TARGET_REG_NAMES_P TRUE
static void s390_insn (int);
static void s390_literals (int);
static void s390_machine (int);
+static void s390_machinemode (int);
const pseudo_typeS md_pseudo_table[] =
{
- { "align", s_align_bytes, 0 },
+ { "align", s_align_bytes, 0 },
/* Pseudo-ops which must be defined. */
- { "bss", s390_bss, 0 },
- { "insn", s390_insn, 0 },
+ { "bss", s390_bss, 0 },
+ { "insn", s390_insn, 0 },
/* Pseudo-ops which must be overridden. */
- { "byte", s390_byte, 0 },
- { "short", s390_elf_cons, 2 },
- { "long", s390_elf_cons, 4 },
- { "quad", s390_elf_cons, 8 },
- { "ltorg", s390_literals, 0 },
- { "string", stringer, 8 + 1 },
- { "machine", s390_machine, 0 },
- { NULL, NULL, 0 }
+ { "byte", s390_byte, 0 },
+ { "short", s390_elf_cons, 2 },
+ { "long", s390_elf_cons, 4 },
+ { "quad", s390_elf_cons, 8 },
+ { "ltorg", s390_literals, 0 },
+ { "string", stringer, 8 + 1 },
+ { "machine", s390_machine, 0 },
+ { "machinemode", s390_machinemode, 0 },
+ { NULL, NULL, 0 }
};
return S390_OPCODE_Z10;
else if (strcmp (arg, "z196") == 0)
return S390_OPCODE_Z196;
+ else if (strcmp (arg, "zEC12") == 0)
+ return S390_OPCODE_ZEC12;
else if (strcmp (arg, "all") == 0)
return S390_OPCODE_MAXCPU - 1;
else
current_mode_mask = 1 << S390_OPCODE_ESA;
else if (arg != NULL && strcmp (arg, "zarch") == 0)
- current_mode_mask = 1 << S390_OPCODE_ZARCH;
+ {
+ if (s390_arch_size == 32)
+ set_highgprs_p = TRUE;
+ current_mode_mask = 1 << S390_OPCODE_ZARCH;
+ }
else if (arg != NULL && strncmp (arg, "arch=", 5) == 0)
{
{
register const struct s390_opcode *op;
const struct s390_opcode *op_end;
- bfd_boolean dup_insn = FALSE;
const char *retval;
/* Give a warning if the combination -m64-bit and -Aesa is used. */
{
retval = hash_insert (s390_opformat_hash, op->name, (void *) op);
if (retval != (const char *) NULL)
- {
- as_bad (_("Internal assembler error for instruction format %s"),
- op->name);
- dup_insn = TRUE;
- }
+ as_bad (_("Internal assembler error for instruction format %s"),
+ op->name);
}
s390_setup_opcodes ();
&& ex.X_add_number == 0
&& warn_areg_zero)
as_warn (_("base register specified but zero"));
+ if ((operand->flags & S390_OPERAND_GPR)
+ && (operand->flags & S390_OPERAND_REG_PAIR)
+ && (ex.X_add_number & 1))
+ as_fatal (_("odd numbered general purpose register specified as "
+ "register pair"));
+ if ((operand->flags & S390_OPERAND_FPR)
+ && (operand->flags & S390_OPERAND_REG_PAIR)
+ && ex.X_add_number != 0 && ex.X_add_number != 1
+ && ex.X_add_number != 4 && ex.X_add_number != 5
+ && ex.X_add_number != 8 && ex.X_add_number != 9
+ && ex.X_add_number != 12 && ex.X_add_number != 13)
+ as_fatal (_("invalid floating point register pair. Valid fp "
+ "register pair operands are 0, 1, 4, 5, 8, 9, "
+ "12 or 13."));
s390_insert_operand (insn, operand, ex.X_add_number, NULL, 0);
}
}
/* The .machine pseudo op allows to switch to a different CPU level in
the asm listing. The current CPU setting can be stored on a stack
- with .machine push and restored with .machined pop. */
+ with .machine push and restored with .machine pop. */
static void
s390_machine (int ignore ATTRIBUTE_UNUSED)
demand_empty_rest_of_line ();
}
+/* The .machinemode pseudo op allows to switch to a different
+ architecture mode in the asm listing. The current architecture
+ mode setting can be stored on a stack with .machinemode push and
+ restored with .machinemode pop. */
+
+static void
+s390_machinemode (int ignore ATTRIBUTE_UNUSED)
+{
+ char *mode_string;
+#define MAX_HISTORY 100
+ static unsigned int *mode_history;
+ static int curr_hist;
+
+ SKIP_WHITESPACE ();
+
+ if (*input_line_pointer == '"')
+ {
+ int len;
+ mode_string = demand_copy_C_string (&len);
+ }
+ else
+ {
+ char c;
+ mode_string = input_line_pointer;
+ c = get_symbol_end ();
+ mode_string = xstrdup (mode_string);
+ *input_line_pointer = c;
+ }
+
+ if (mode_string != NULL)
+ {
+ unsigned int old_mode_mask = current_mode_mask;
+ char *p;
+
+ for (p = mode_string; *p != 0; p++)
+ *p = TOLOWER (*p);
+
+ if (strcmp (mode_string, "push") == 0)
+ {
+ if (mode_history == NULL)
+ mode_history = xmalloc (MAX_HISTORY * sizeof (*mode_history));
+
+ if (curr_hist >= MAX_HISTORY)
+ as_bad (_(".machinemode stack overflow"));
+ else
+ mode_history[curr_hist++] = current_mode_mask;
+ }
+ else if (strcmp (mode_string, "pop") == 0)
+ {
+ if (curr_hist <= 0)
+ as_bad (_(".machinemode stack underflow"));
+ else
+ current_mode_mask = mode_history[--curr_hist];
+ }
+ else
+ {
+ if (strcmp (mode_string, "esa") == 0)
+ current_mode_mask = 1 << S390_OPCODE_ESA;
+ else if (strcmp (mode_string, "zarch") == 0)
+ {
+ if (s390_arch_size == 32)
+ set_highgprs_p = TRUE;
+ current_mode_mask = 1 << S390_OPCODE_ZARCH;
+ }
+ else if (strcmp (mode_string, "zarch_nohighgprs") == 0)
+ current_mode_mask = 1 << S390_OPCODE_ZARCH;
+ else
+ as_bad (_("invalid machine `%s'"), mode_string);
+ }
+
+ if (current_mode_mask != old_mode_mask)
+ s390_setup_opcodes ();
+ }
+
+ demand_empty_rest_of_line ();
+}
+
char *
md_atof (int type, char *litp, int *sizep)
{
case BFD_RELOC_390_GOTPLTENT:
return 1;
default:
- break;;
+ break;
}
return generic_force_reloc (fixp);
void
s390_elf_final_processing (void)
{
- if (s390_arch_size == 32 && (current_mode_mask & (1 << S390_OPCODE_ZARCH)))
+ if (set_highgprs_p)
elf_elfheader (stdoutput)->e_flags |= EF_S390_HIGH_GPRS;
}