+ if (current_architecture == cpuxgate)
+ {
+ /* Find the opcode definition given its name. */
+ opc = (struct m68hc11_opcode_def *) hash_find (m68hc11_hash, name);
+ if (opc == NULL)
+ {
+ as_bad (_("Opcode `%s' is not recognized."), name);
+ return;
+ }
+
+ /* Grab a local copy. */
+ opcode_local.name = opc->opcode->name;
+ /* These will be incomplete where multiple variants exist. */
+ opcode_local.opcode = opc->opcode->opcode;
+ opcode_local.format = opc->opcode->format;
+
+ save = input_line_pointer;
+ input_line_pointer = (char *) op_end;
+
+ if (opc->format == M68XG_OP_NONE)
+ {
+ /* No special handling required. */
+ opcode_local.format = M68XG_OP_NONE;
+ build_insn_xg (opc->opcode, operands, 0);
+ return;
+ }
+
+ /* Special handling of TFR. */
+ if (strncmp (opc->opcode->name, "tfr",3) == 0)
+ {
+ /* There must be two operands with a comma. */
+ input_line_pointer = skip_whites (input_line_pointer);
+ operands[0].reg1 = register_name ();
+ if (operands[0].reg1 == REG_NONE)
+ {
+ as_bad ("Invalid register\n");
+ return;
+ }
+ input_line_pointer = skip_whites (input_line_pointer);
+ if (*input_line_pointer != ',')
+ {
+ as_bad ("Missing comma.\n");
+ return;
+ }
+ input_line_pointer++;
+ input_line_pointer = skip_whites (input_line_pointer);
+ operands[1].reg1 = register_name ();
+ if (operands[1].reg1 == REG_NONE)
+ {
+ as_bad ("Invalid register\n");
+ return;
+ }
+ input_line_pointer = skip_whites (input_line_pointer);
+ if (*input_line_pointer != '\n' && *input_line_pointer)
+ {
+ as_bad (_("Garbage at end of instruction: `%s'."),
+ input_line_pointer);
+ return;
+ }
+ if (operands[1].reg1 == REG_CCR) /* ,CCR */
+ opc->opcode->opcode = 0x00f8 | ( operands[0].reg1 << 8);
+ else if (operands[0].reg1 == REG_CCR) /* CCR, */
+ opc->opcode->opcode = 0x00f9 | ( operands[1].reg1 << 8);
+ else if (operands[1].reg1 == REG_PC) /* ,PC */
+ opc->opcode->opcode = 0x00fa | ( operands[0].reg1 << 8);
+ else
+ {
+ as_bad ("Invalid operand to TFR\n");
+ return;
+ }
+ /* no special handling required */
+ opcode_local.format = M68XG_OP_NONE;
+ opcode_local.opcode = opc->opcode->opcode;
+ build_insn_xg (&opcode_local, operands, 0);
+ return;
+ }
+
+ /* CSEM, SSEM */
+ if (opc->format & M68XG_OP_IMM3)
+ {
+ /* Either IMM3 or R */
+ input_line_pointer = skip_whites (input_line_pointer);
+ if ((*input_line_pointer == 'R') || (*input_line_pointer == 'r'))
+ {
+ operands[0].reg1 = register_name ();
+ if (operands[0].reg1 == REG_NONE)
+ {
+ as_bad ("Invalid register\n");
+ return;
+ }
+ operands[0].mode = M68XG_OP_R;
+ /* One opcode has multiple modes, so find right one. */
+ opcode = find (opc, operands, 1);
+ if (opcode)
+ {
+ opcode_local.opcode = opcode->opcode
+ | (operands[0].reg1 << 8);
+ opcode_local.format = M68XG_OP_NONE;
+ build_insn_xg (&opcode_local, operands, 1);
+ }
+ else
+ as_bad ("No opcode found\n");
+
+ return;
+ }
+ else
+ {
+ if (*input_line_pointer == '#')
+ input_line_pointer++;
+
+ expression (&operands[0].exp);
+ if (operands[0].exp.X_op == O_illegal)
+ {
+ as_bad (_("Illegal operand."));
+ return;
+ }
+ else if (operands[0].exp.X_op == O_absent)
+ {
+ as_bad (_("Missing operand."));
+ return;
+ }
+
+ if (check_range (operands[0].exp.X_add_number,M68XG_OP_IMM3))
+ {
+ opcode_local.opcode |= (operands[0].exp.X_add_number);
+ operands[0].mode = M68XG_OP_IMM3;
+
+ opcode = find (opc, operands, 1);
+ if (opcode)
+ {
+ opcode_local.opcode = opcode->opcode;
+ opcode_local.opcode
+ |= (operands[0].exp.X_add_number) << 8;
+ opcode_local.format = M68XG_OP_NONE;
+ build_insn_xg (&opcode_local, operands, 1);
+ }
+ else
+ as_bad ("No opcode found\n");
+
+ return;
+ }
+ else
+ {
+ as_bad ("Number out of range for IMM3\n");
+ return;
+ }
+ }
+ }
+
+ /* Special handling of SIF. */
+ if (strncmp (opc->opcode->name, "sif",3) == 0)
+ {
+ /* Either OP_NONE or OP_RS. */
+ if (*input_line_pointer != '\n')
+ input_line_pointer = skip_whites (input_line_pointer);
+
+ if ((*input_line_pointer == '\n') || (*input_line_pointer == '\r')
+ || (*input_line_pointer == '\0'))
+ opc->opcode->opcode = 0x0300;
+ else
+ {
+ operands[0].reg1 = register_name ();
+ if (operands[0].reg1 == REG_NONE)
+ {
+ as_bad ("Invalid register\n");
+ return;
+ }
+ opcode_local.opcode = 0x00f7 | (operands[0].reg1 << 8);
+ }
+ opcode_local.format = M68XG_OP_NONE;
+ build_insn_xg (&opcode_local, operands, 0);
+ return;
+ }
+
+ /* SEX, PAR, JAL plus aliases NEG, TST, COM */
+ if (opc->format & M68XG_OP_R)
+ {
+ input_line_pointer = skip_whites (input_line_pointer);
+ operands[0].reg1 = register_name ();
+ if (operands[0].reg1 == REG_NONE)
+ {
+ as_bad ("Invalid register\n");
+ return;
+ }
+ if ((*input_line_pointer == '\n') || (*input_line_pointer == '\r')
+ || (*input_line_pointer == '\0'))
+ {
+ /* Likely to be OP R. */
+ if (opc->format & M68XG_OP_R)
+ {
+ operands[0].mode = M68XG_OP_R;
+
+ opcode = find (opc, operands, 1);
+ if (opcode)
+ {
+ if ((strncmp (opc->opcode->name, "com",3) == 0)
+ || (strncmp (opc->opcode->name, "neg",3) == 0))
+ /* Special case for com RD as alias for sub RD,R0,RS */
+ /* Special case for neg RD as alias for sub RD,R0,RS */
+ opcode_local.opcode = opcode->opcode
+ | (operands[0].reg1 << 8) | (operands[0].reg1 << 2);
+ else if (strncmp (opc->opcode->name, "tst",3) == 0)
+ /* Special case for tst RS alias for sub R0, RS, R0 */
+ opcode_local.opcode = opcode->opcode
+ | (operands[0].reg1 << 5);
+ else
+ opcode_local.opcode |= (operands[0].reg1 << 8);
+ }
+ opcode_local.format = M68XG_OP_NONE;
+ build_insn_xg (&opcode_local, operands, 0);
+ }
+ else
+ as_bad ("No valid mode found\n");
+
+ return;
+ }
+ }
+
+ if (opc->format & (M68XG_OP_REL9 | M68XG_OP_REL10))
+ {
+ opcode_local.format = opc->format;
+ input_line_pointer = skip_whites (input_line_pointer);
+ expression (&operands[0].exp);
+ if (operands[0].exp.X_op == O_illegal)
+ {
+ as_bad (_("Illegal operand."));
+ return;
+ }
+ else if (operands[0].exp.X_op == O_absent)
+ {
+ as_bad (_("Missing operand."));
+ return;
+ }
+ opcode_local.opcode = opc->opcode->opcode;
+ build_insn_xg (&opcode_local, operands, 1);
+ return;
+ }
+
+
+ /* For other command formats, parse input line and determine the mode
+ we are using as we go. */
+
+ input_line_pointer = skip_whites (input_line_pointer);
+ if ((*input_line_pointer == '\n') || (*input_line_pointer == '\r')
+ || (*input_line_pointer == '\0'))
+ return; /* nothing left */
+
+ if (*input_line_pointer == '#')
+ {
+ as_bad ("No register specified before hash\n");
+ return;
+ }
+
+ /* first operand is expected to be a register */
+ if ((*input_line_pointer == 'R') || (*input_line_pointer == 'r'))
+ {
+ operands[0].reg1 = register_name ();
+ if (operands[0].reg1 == REG_NONE)
+ {
+ as_bad ("Invalid register\n");
+ return;
+ }
+ }
+
+ input_line_pointer = skip_whites (input_line_pointer);
+ if (*input_line_pointer != ',')
+ {
+ as_bad ("Missing operand\n");
+ return;
+ }
+ input_line_pointer++;
+ input_line_pointer = skip_whites (input_line_pointer);
+
+ if (*input_line_pointer == '#')
+ {
+ /* Some kind of immediate mode, check if this is possible. */
+ if (!(opc->format
+ & (M68XG_OP_R_IMM8 | M68XG_OP_R_IMM16 | M68XG_OP_R_IMM4)))
+ as_bad ("Invalid immediate mode for `%s'", opc->opcode->name);
+ else
+ {
+ input_line_pointer++;
+ input_line_pointer = skip_whites (input_line_pointer);
+ if (strncmp (input_line_pointer, "%hi", 3) == 0)
+ {
+ input_line_pointer += 3;
+ operands[0].mode = M6811_OP_HIGH_ADDR;
+ }
+ else if (strncmp (input_line_pointer, "%lo", 3) == 0)
+ {
+ input_line_pointer += 3;
+ operands[0].mode = M6811_OP_LOW_ADDR;
+ }
+ else
+ operands[0].mode = 0;
+
+ expression (&operands[0].exp);
+ if (operands[0].exp.X_op == O_illegal)
+ {
+ as_bad (_("Illegal operand."));
+ return;
+ }
+ else if (operands[0].exp.X_op == O_absent)
+ {
+ as_bad (_("Missing operand."));
+ return;
+ }
+ /* ok so far, can only be one mode */
+ opcode_local.format = opc->format
+ & (M68XG_OP_R_IMM8 | M68XG_OP_R_IMM16 | M68XG_OP_R_IMM4);
+ if (opcode_local.format & M68XG_OP_R_IMM4)
+ {
+ operands[0].mode = M68XG_OP_R_IMM4;
+ /* same opcodes have multiple modes, so find right one */
+ opcode = find (opc, operands, 1);
+ if (opcode)
+ opcode_local.opcode = opcode->opcode
+ | (operands[0].reg1 << 8);
+
+ if (operands[0].exp.X_op != O_constant)
+ as_bad ("Only constants supported at for IMM4 mode\n");
+ else
+ {
+ if (check_range
+ (operands[0].exp.X_add_number,M68XG_OP_R_IMM4))
+ opcode_local.opcode
+ |= (operands[0].exp.X_add_number << 4);
+ else
+ as_bad ("Number out of range for IMM4\n");
+ }
+ opcode_local.format = M68XG_OP_NONE;
+ }
+ else if (opcode_local.format & M68XG_OP_R_IMM16)
+ {
+ operands[0].mode = M68XG_OP_R_IMM16;
+
+ opcode = find (opc, operands, 1);
+ if (opcode)
+ {
+ opcode_local.opcode = opcode->opcode
+ | (operands[0].reg1 << 8);
+ }
+ }
+ else
+ {
+ opcode_local.opcode = opc->opcode->opcode
+ | (operands[0].reg1 << 8);
+ }
+ build_insn_xg (&opcode_local, operands, 1);
+ }
+ }
+ else if ((*input_line_pointer == 'R') || (*input_line_pointer == 'r'))
+ {
+ /* we've got as far as OP R, R */
+ operands[1].reg1 = register_name ();
+ if (operands[1].reg1 == REG_NONE)
+ {
+ as_bad ("Invalid register\n");
+ return;
+ }
+ if ((*input_line_pointer == '\n') || (*input_line_pointer == '\r')
+ || (*input_line_pointer == '\0'))
+ {
+ /* looks like OP_R_R */
+ if (opc->format & M68XG_OP_R_R)
+ {
+ operands[0].mode = M68XG_OP_R_R;
+ /* same opcodes have multiple modes, so find right one */
+ opcode = find (opc, operands, 1);
+ if (opcode)
+ {
+ if ((strncmp (opc->opcode->name, "com",3) == 0)
+ || (strncmp (opc->opcode->name, "mov",3) == 0)
+ || (strncmp (opc->opcode->name, "neg",3) == 0))
+ {
+ /* Special cases for:
+ com RD, RS alias for xnor RD,R0,RS
+ mov RD, RS alias for or RD, R0, RS
+ neg RD, RS alias for sub RD, R0, RS */
+ opcode_local.opcode = opcode->opcode
+ | (operands[0].reg1 << 8) | (operands[1].reg1 << 2);
+ }
+ else if ((strncmp (opc->opcode->name, "cmp",3) == 0)
+ || (strncmp (opc->opcode->name, "cpc",3) == 0))
+ {
+ /* special cases for:
+ cmp RS1, RS2 alias for sub R0, RS1, RS2
+ cpc RS1, RS2 alias for sbc R0, RS1, RS2 */
+ opcode_local.opcode = opcode->opcode
+ | (operands[0].reg1 << 5) | (operands[1].reg1 << 2);
+ }
+ else
+ {
+ opcode_local.opcode = opcode->opcode
+ | (operands[0].reg1 << 8) | (operands[1].reg1 << 5);
+ }
+ opcode_local.format = M68XG_OP_NONE;
+ build_insn_xg (&opcode_local, operands, 1);
+ }
+ }
+ else
+ {
+ as_bad ("No valid mode found\n");
+ }
+ }
+ else
+ {
+ /* more data */
+ if (*input_line_pointer != ',')
+ {
+ as_bad (_("Missing operand."));
+ return;
+ }
+ input_line_pointer++;
+ input_line_pointer = skip_whites (input_line_pointer);
+ if ((*input_line_pointer == 'R') || (*input_line_pointer == 'r'))
+ {
+ operands[2].reg1 = register_name ();
+ if (operands[2].reg1 == REG_NONE)
+ {
+ as_bad ("Invalid register\n");
+ return;
+ }
+ if (opc->format & M68XG_OP_R_R_R)
+ {
+ operands[0].mode = M68XG_OP_R_R_R;
+
+ opcode = find (opc, operands, 1);
+ if (opcode)
+ {
+ opcode_local.opcode = opcode->opcode
+ | (operands[0].reg1 << 8) | (operands[1].reg1 << 5)
+ | (operands[2].reg1 << 2);
+ opcode_local.format = M68XG_OP_NONE;
+ build_insn_xg (&opcode_local, operands, 1);
+ }
+ }
+ else
+ {
+ as_bad ("No valid mode found\n");
+ }
+ }
+ }
+ }
+ else if (*input_line_pointer == '(') /* Indexed modes */
+ {
+ input_line_pointer++;
+ input_line_pointer = skip_whites (input_line_pointer);
+ if ((*input_line_pointer == 'R') || (*input_line_pointer == 'r'))
+ {
+ /* we've got as far as OP R, (R */
+ operands[1].reg1 = register_name ();
+ if (operands[1].reg1 == REG_NONE)
+ {
+ as_bad ("Invalid register\n");
+ return;
+ }
+
+ if ((*input_line_pointer == '\n') || (*input_line_pointer == '\r')
+ || (*input_line_pointer == '\0'))
+ {
+ /* Looks like OP_R_R. */
+ as_bad (_("Missing operand."));
+ return;
+ }
+
+ input_line_pointer = skip_whites (input_line_pointer);
+
+ if (*input_line_pointer != ',')
+ {
+ as_bad (_("Missing operand."));
+ return;
+ }
+ input_line_pointer++;
+ input_line_pointer = skip_whites (input_line_pointer);
+
+ if (*input_line_pointer == '#')
+ {
+ input_line_pointer++;
+ input_line_pointer = skip_whites (input_line_pointer);
+ expression (&operands[0].exp);
+ if (operands[0].exp.X_op == O_illegal)
+ {
+ as_bad (_("Illegal operand."));
+ return;
+ }
+ else if (operands[0].exp.X_op == O_absent)
+ {
+ as_bad (_("Missing operand."));
+ return;
+ }
+
+ input_line_pointer = skip_whites (input_line_pointer);
+ if (*input_line_pointer != ')')
+ {
+ as_bad ("Missing `)' to close register indirect operand.");
+ return;
+ }
+ else
+ {
+ input_line_pointer++;
+ }
+
+ /* Ok so far, can only be one mode. */
+ opcode_local.format = M68XG_OP_R_R_OFFS5;
+ operands[0].mode = M68XG_OP_R_R_OFFS5;
+
+ opcode = find (opc, operands, 1);
+ if (opcode)
+ {
+ opcode_local.opcode = opcode->opcode
+ | (operands[0].reg1 << 8) | (operands[1].reg1 << 5);
+ if (operands[0].exp.X_op != O_constant)
+ {
+ as_bad
+ ("Only constants supported for indexed OFFS5 mode\n");
+ }
+ else
+ {
+ if (check_range (operands[0].exp.X_add_number,
+ M68XG_OP_R_R_OFFS5))
+ {
+ opcode_local.opcode
+ |= (operands[0].exp.X_add_number);
+ opcode_local.format = M68XG_OP_NONE;
+ build_insn_xg (&opcode_local, operands, 1);
+ }
+ else
+ {
+ as_bad ("Number out of range for OFFS5\n");
+ }
+ }
+ }
+ }
+ else
+ {
+ operands[0].mode = M68XG_OP_RD_RB_RI;
+
+ if (*input_line_pointer == '-')
+ {
+ operands[0].mode = M68XG_OP_RD_RB_mRI;
+ input_line_pointer++;
+ }
+ operands[2].reg1 = register_name ();
+ if (operands[2].reg1 == REG_NONE)
+ {
+ as_bad ("Invalid register\n");
+ return;
+ }
+
+ if (*input_line_pointer == '+')
+ {
+ if (opcode_local.format == M68XG_OP_RD_RB_mRI)
+ {
+ as_bad (_("Illegal operand."));
+ return;
+ }
+ operands[0].mode = M68XG_OP_RD_RB_RIp;
+ input_line_pointer++;
+ }
+
+ input_line_pointer = skip_whites (input_line_pointer);
+ if (*input_line_pointer != ')')
+ {
+ as_bad
+ ("Missing `)' to close register indirect operand.");
+ return;
+ }
+ else
+ {
+ input_line_pointer++;
+ }
+
+ opcode = find (opc, operands, 1);
+ if (opcode)
+ {
+ opcode_local.opcode = opcode->opcode
+ | (operands[0].reg1 << 8) | (operands[1].reg1 << 5)
+ | (operands[2].reg1 << 2);
+ opcode_local.format = M68XG_OP_NONE;
+ build_insn_xg (&opcode_local, operands, 1);
+ }
+ else
+ {
+ as_bad ("Failed to find opcode for %s %s\n",
+ opc->opcode->name, (char *)op_end);
+ }
+ }
+ }
+ }
+ else
+ {
+ as_bad (_("Failed to find a valid mode for `%s'."),
+ opc->opcode->name);
+ }
+
+ if (opc->opcode && !flag_mri)
+ {
+ char *p = input_line_pointer;
+
+ while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')
+ p++;
+
+ if (*p != '\n' && *p)
+ as_bad (_("Garbage at end of instruction: `%s'."), p);
+ }
+
+ input_line_pointer = save;
+
+ /* Opcode is known but does not have valid operands. Print out the
+ syntax for this opcode. */
+ if (opc->opcode == 0)
+ {
+ if (flag_print_insn_syntax)
+ print_insn_format (name);
+
+ as_bad (_("Invalid operand for `%s'"), name);
+ return;
+ }
+
+ return;
+ }
+