+ debug ("In md_assemble() with argument %s\n", line);
+ memset (&insn, '\0', sizeof (insn));
+ if (found_parallel_insn)
+ {
+ debug ("Line is second part of parallel instruction\n\n");
+ found_parallel_insn = 0;
+ return;
+ }
+ if ((current_posn =
+ tic30_find_parallel_insn (line, input_line_pointer + 1)) == NULL)
+ current_posn = line;
+ else
+ found_parallel_insn = 1;
+
+ while (is_space_char (*current_posn))
+ current_posn++;
+
+ token_start = current_posn;
+
+ if (!is_opcode_char (*current_posn))
+ {
+ as_bad (_("Invalid character %s in opcode"),
+ output_invalid (*current_posn));
+ return;
+ }
+ /* Check if instruction is a parallel instruction
+ by seeing if the first character is a q. */
+ if (*token_start == 'q')
+ {
+ if (tic30_parallel_insn (token_start))
+ {
+ if (found_parallel_insn)
+ free (token_start);
+ return;
+ }
+ }
+ while (is_opcode_char (*current_posn))
+ current_posn++;
+ {
+ /* Find instruction. */
+ save_char = *current_posn;
+ *current_posn = '\0';
+ op = (insn_template *) hash_find (op_hash, token_start);
+ if (op)
+ {
+ debug ("Found instruction %s\n", op->name);
+ insn.tm = op;
+ }
+ else
+ {
+ debug ("Didn't find insn\n");
+ as_bad (_("Unknown TMS320C30 instruction: %s"), token_start);
+ return;
+ }
+ *current_posn = save_char;
+ }
+
+ if (*current_posn != END_OF_INSN)
+ {
+ /* Find operands. */
+ int paren_not_balanced;
+ int expecting_operand = 0;
+ int this_operand;
+ do
+ {
+ /* Skip optional white space before operand. */
+ while (!is_operand_char (*current_posn)
+ && *current_posn != END_OF_INSN)
+ {
+ if (!is_space_char (*current_posn))
+ {
+ as_bad (_("Invalid character %s before %s operand"),
+ output_invalid (*current_posn),
+ ordinal_names[insn.operands]);
+ return;
+ }
+ current_posn++;
+ }
+ token_start = current_posn;
+ paren_not_balanced = 0;
+ while (paren_not_balanced || *current_posn != ',')
+ {
+ if (*current_posn == END_OF_INSN)
+ {
+ if (paren_not_balanced)
+ {
+ as_bad (_("Unbalanced parenthesis in %s operand."),
+ ordinal_names[insn.operands]);
+ return;
+ }
+ else
+ break;
+ }
+ else if (!is_operand_char (*current_posn)
+ && !is_space_char (*current_posn))
+ {
+ as_bad (_("Invalid character %s in %s operand"),
+ output_invalid (*current_posn),
+ ordinal_names[insn.operands]);
+ return;
+ }
+ if (*current_posn == '(')
+ ++paren_not_balanced;
+ if (*current_posn == ')')
+ --paren_not_balanced;
+ current_posn++;
+ }
+ if (current_posn != token_start)
+ {
+ /* Yes, we've read in another operand. */
+ this_operand = insn.operands++;
+ if (insn.operands > MAX_OPERANDS)
+ {
+ as_bad (_("Spurious operands; (%d operands/instruction max)"),
+ MAX_OPERANDS);
+ return;
+ }
+
+ /* Now parse operand adding info to 'insn' as we go along. */
+ save_char = *current_posn;
+ *current_posn = '\0';
+ insn.operand_type[this_operand] = tic30_operand (token_start);
+ *current_posn = save_char;
+ if (insn.operand_type[this_operand] == NULL)
+ return;
+ }
+ else
+ {
+ if (expecting_operand)
+ {
+ as_bad (_("Expecting operand after ','; got nothing"));
+ return;
+ }
+ if (*current_posn == ',')
+ {
+ as_bad (_("Expecting operand before ','; got nothing"));
+ return;
+ }
+ }
+
+ /* Now *current_posn must be either ',' or END_OF_INSN. */
+ if (*current_posn == ',')
+ {
+ if (*++current_posn == END_OF_INSN)
+ {
+ /* Just skip it, if it's \n complain. */
+ as_bad (_("Expecting operand after ','; got nothing"));
+ return;
+ }
+ expecting_operand = 1;
+ }
+ }
+ while (*current_posn != END_OF_INSN);
+ }
+
+ debug ("Number of operands found: %d\n", insn.operands);
+
+ /* Check that number of operands is correct. */
+ if (insn.operands != insn.tm->operands)
+ {
+ unsigned int i;
+ unsigned int numops = insn.tm->operands;
+
+ /* If operands are not the same, then see if any of the operands are
+ not required. Then recheck with number of given operands. If they
+ are still not the same, then give an error, otherwise carry on. */
+ for (i = 0; i < insn.tm->operands; i++)
+ if (insn.tm->operand_types[i] & NotReq)
+ numops--;
+ if (insn.operands != numops)
+ {
+ as_bad (_("Incorrect number of operands given"));
+ return;
+ }
+ }
+ insn.addressing_mode = AM_NotReq;
+ for (count = 0; count < insn.operands; count++)
+ {
+ if (insn.operand_type[count]->op_type & insn.tm->operand_types[count])
+ {
+ debug ("Operand %d matches\n", count + 1);
+ /* If instruction has two operands and has an AddressMode
+ modifier then set addressing mode type for instruction. */
+ if (insn.tm->opcode_modifier == AddressMode)
+ {
+ int addr_insn = 0;
+ /* Store instruction uses the second
+ operand for the address mode. */
+ if ((insn.tm->operand_types[1] & (Indirect | Direct))
+ == (Indirect | Direct))
+ addr_insn = 1;
+
+ if (insn.operand_type[addr_insn]->op_type & (AllReg))
+ insn.addressing_mode = AM_Register;
+ else if (insn.operand_type[addr_insn]->op_type & Direct)
+ insn.addressing_mode = AM_Direct;
+ else if (insn.operand_type[addr_insn]->op_type & Indirect)
+ insn.addressing_mode = AM_Indirect;
+ else
+ insn.addressing_mode = AM_Immediate;
+ }
+ }
+ else
+ {
+ as_bad (_("The %s operand doesn't match"), ordinal_names[count]);
+ return;
+ }
+ }
+
+ /* Now set the addressing mode for 3 operand instructions. */
+ if ((insn.tm->operand_types[0] & op3T1)
+ && (insn.tm->operand_types[1] & op3T2))
+ {
+ /* Set the addressing mode to the values used for 2 operand
+ instructions in the G addressing field of the opcode. */
+ char *p;
+ switch (insn.operand_type[0]->op_type)
+ {
+ case Rn:
+ case ARn:
+ case DPReg:
+ case OtherReg:
+ if (insn.operand_type[1]->op_type & (AllReg))
+ insn.addressing_mode = AM_Register;
+ else if (insn.operand_type[1]->op_type & Indirect)
+ insn.addressing_mode = AM_Direct;
+ else
+ {
+ /* Shouldn't make it to this stage. */
+ as_bad (_("Incompatible first and second operands in instruction"));
+ return;
+ }
+ break;
+ case Indirect:
+ if (insn.operand_type[1]->op_type & (AllReg))
+ insn.addressing_mode = AM_Indirect;
+ else if (insn.operand_type[1]->op_type & Indirect)
+ insn.addressing_mode = AM_Immediate;
+ else
+ {
+ /* Shouldn't make it to this stage. */
+ as_bad (_("Incompatible first and second operands in instruction"));
+ return;
+ }
+ break;
+ }
+ /* Now make up the opcode for the 3 operand instructions. As in
+ parallel instructions, there will be no unresolved values, so they
+ can be fully formed and added to the frag table. */
+ insn.opcode = insn.tm->base_opcode;
+ if (insn.operand_type[0]->op_type & Indirect)
+ {
+ insn.opcode |= (insn.operand_type[0]->indirect.ARnum);
+ insn.opcode |= (insn.operand_type[0]->indirect.mod << 3);
+ }
+ else
+ insn.opcode |= (insn.operand_type[0]->reg.opcode);
+
+ if (insn.operand_type[1]->op_type & Indirect)
+ {
+ insn.opcode |= (insn.operand_type[1]->indirect.ARnum << 8);
+ insn.opcode |= (insn.operand_type[1]->indirect.mod << 11);
+ }
+ else
+ insn.opcode |= (insn.operand_type[1]->reg.opcode << 8);
+
+ if (insn.operands == 3)
+ insn.opcode |= (insn.operand_type[2]->reg.opcode << 16);
+
+ insn.opcode |= insn.addressing_mode;
+ p = frag_more (INSN_SIZE);
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ }
+ else
+ {
+ /* Not a three operand instruction. */
+ char *p;
+ int am_insn = -1;
+ insn.opcode = insn.tm->base_opcode;
+ /* Create frag for instruction - all instructions are 4 bytes long. */
+ p = frag_more (INSN_SIZE);
+ if ((insn.operands > 0) && (insn.tm->opcode_modifier == AddressMode))
+ {
+ insn.opcode |= insn.addressing_mode;
+ if (insn.addressing_mode == AM_Indirect)
+ {
+ /* Determine which operand gives the addressing mode. */
+ if (insn.operand_type[0]->op_type & Indirect)
+ am_insn = 0;
+ if ((insn.operands > 1)
+ && (insn.operand_type[1]->op_type & Indirect))
+ am_insn = 1;
+ insn.opcode |= (insn.operand_type[am_insn]->indirect.disp);
+ insn.opcode |= (insn.operand_type[am_insn]->indirect.ARnum << 8);
+ insn.opcode |= (insn.operand_type[am_insn]->indirect.mod << 11);
+ if (insn.operands > 1)
+ insn.opcode |= (insn.operand_type[!am_insn]->reg.opcode << 16);
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ }
+ else if (insn.addressing_mode == AM_Register)
+ {
+ insn.opcode |= (insn.operand_type[0]->reg.opcode);
+ if (insn.operands > 1)
+ insn.opcode |= (insn.operand_type[1]->reg.opcode << 16);
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ }
+ else if (insn.addressing_mode == AM_Direct)
+ {
+ if (insn.operand_type[0]->op_type & Direct)
+ am_insn = 0;
+ if ((insn.operands > 1)
+ && (insn.operand_type[1]->op_type & Direct))
+ am_insn = 1;
+ if (insn.operands > 1)
+ insn.opcode |=
+ (insn.operand_type[! am_insn]->reg.opcode << 16);
+ if (insn.operand_type[am_insn]->direct.resolved == 1)
+ {
+ /* Resolved values can be placed straight
+ into instruction word, and output. */
+ insn.opcode |=
+ (insn.operand_type[am_insn]->direct.address & 0x0000FFFF);
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ }
+ else
+ {
+ /* Unresolved direct addressing mode instruction. */
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ fix_new_exp (frag_now, p + 2 - (frag_now->fr_literal), 2,
+ & insn.operand_type[am_insn]->direct.direct_expr,
+ 0, 0);
+ }
+ }
+ else if (insn.addressing_mode == AM_Immediate)
+ {
+ if (insn.operand_type[0]->immediate.resolved == 1)
+ {
+ char *keeploc;
+ int size;
+
+ if (insn.operands > 1)
+ insn.opcode |= (insn.operand_type[1]->reg.opcode << 16);
+
+ switch (insn.tm->imm_arg_type)
+ {
+ case Imm_Float:
+ debug ("Floating point first operand\n");
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+
+ keeploc = input_line_pointer;
+ input_line_pointer =
+ insn.operand_type[0]->immediate.label;
+
+ if (md_atof ('f', p + 2, & size) != 0)
+ {
+ as_bad (_("invalid short form floating point immediate operand"));
+ return;
+ }
+
+ input_line_pointer = keeploc;
+ break;
+
+ case Imm_UInt:
+ debug ("Unsigned int first operand\n");
+ if (insn.operand_type[0]->immediate.decimal_found)
+ as_warn (_("rounding down first operand float to unsigned int"));
+ if (insn.operand_type[0]->immediate.u_number > 0xFFFF)
+ as_warn (_("only lower 16-bits of first operand are used"));
+ insn.opcode |=
+ (insn.operand_type[0]->immediate.u_number & 0x0000FFFFL);
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ break;
+
+ case Imm_SInt:
+ debug ("Int first operand\n");
+
+ if (insn.operand_type[0]->immediate.decimal_found)
+ as_warn (_("rounding down first operand float to signed int"));
+
+ if (insn.operand_type[0]->immediate.s_number < -32768 ||
+ insn.operand_type[0]->immediate.s_number > 32767)
+ {
+ as_bad (_("first operand is too large for 16-bit signed int"));
+ return;
+ }
+ insn.opcode |=
+ (insn.operand_type[0]->immediate.s_number & 0x0000FFFFL);
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ break;
+ }
+ }
+ else
+ {
+ /* Unresolved immediate label. */
+ if (insn.operands > 1)
+ insn.opcode |= (insn.operand_type[1]->reg.opcode << 16);
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ fix_new_exp (frag_now, p + 2 - (frag_now->fr_literal), 2,
+ & insn.operand_type[0]->immediate.imm_expr,
+ 0, 0);
+ }
+ }
+ }
+ else if (insn.tm->opcode_modifier == PCRel)
+ {
+ /* Conditional Branch and Call instructions. */
+ if ((insn.tm->operand_types[0] & (AllReg | Disp))
+ == (AllReg | Disp))
+ {
+ if (insn.operand_type[0]->op_type & (AllReg))
+ {
+ insn.opcode |= (insn.operand_type[0]->reg.opcode);
+ insn.opcode |= PC_Register;
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ }
+ else
+ {
+ insn.opcode |= PC_Relative;
+ if (insn.operand_type[0]->immediate.resolved == 1)
+ {
+ insn.opcode |=
+ (insn.operand_type[0]->immediate.s_number & 0x0000FFFF);
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ }
+ else
+ {
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ fix_new_exp (frag_now, p + 2 - (frag_now->fr_literal),
+ 2, & insn.operand_type[0]->immediate.imm_expr,
+ 1, 0);
+ }
+ }
+ }
+ else if ((insn.tm->operand_types[0] & ARn) == ARn)
+ {
+ /* Decrement and Branch instructions. */
+ insn.opcode |= ((insn.operand_type[0]->reg.opcode - 0x08) << 22);
+ if (insn.operand_type[1]->op_type & (AllReg))
+ {
+ insn.opcode |= (insn.operand_type[1]->reg.opcode);
+ insn.opcode |= PC_Register;
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ }
+ else if (insn.operand_type[1]->immediate.resolved == 1)
+ {
+ if (insn.operand_type[0]->immediate.decimal_found)
+ {
+ as_bad (_("first operand is floating point"));
+ return;
+ }
+ if (insn.operand_type[0]->immediate.s_number < -32768 ||
+ insn.operand_type[0]->immediate.s_number > 32767)
+ {
+ as_bad (_("first operand is too large for 16-bit signed int"));
+ return;
+ }
+ insn.opcode |= (insn.operand_type[1]->immediate.s_number);
+ insn.opcode |= PC_Relative;
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ }
+ else
+ {
+ insn.opcode |= PC_Relative;
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ fix_new_exp (frag_now, p + 2 - frag_now->fr_literal, 2,
+ & insn.operand_type[1]->immediate.imm_expr,
+ 1, 0);
+ }
+ }
+ }
+ else if (insn.tm->operand_types[0] == IVector)
+ {
+ /* Trap instructions. */
+ if (insn.operand_type[0]->op_type & IVector)
+ insn.opcode |= (insn.operand_type[0]->immediate.u_number);
+ else
+ {
+ /* Shouldn't get here. */
+ as_bad (_("interrupt vector for trap instruction out of range"));
+ return;
+ }
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ }
+ else if (insn.tm->opcode_modifier == StackOp
+ || insn.tm->opcode_modifier == Rotate)
+ {
+ /* Push, Pop and Rotate instructions. */
+ insn.opcode |= (insn.operand_type[0]->reg.opcode << 16);
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ }
+ else if ((insn.tm->operand_types[0] & (Abs24 | Direct))
+ == (Abs24 | Direct))
+ {
+ /* LDP Instruction needs to be tested
+ for before the next section. */
+ if (insn.operand_type[0]->op_type & Direct)
+ {
+ if (insn.operand_type[0]->direct.resolved == 1)
+ {
+ /* Direct addressing uses lower 8 bits of direct address. */
+ insn.opcode |=
+ (insn.operand_type[0]->direct.address & 0x00FF0000) >> 16;
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ }
+ else
+ {
+ fixS *fix;
+
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ fix = fix_new_exp (frag_now, p + 3 - (frag_now->fr_literal),
+ 1, &insn.operand_type[0]->direct.direct_expr, 0, 0);
+ /* Ensure that the assembler doesn't complain
+ about fitting a 24-bit address into 8 bits. */
+ fix->fx_no_overflow = 1;
+ }
+ }
+ else
+ {
+ if (insn.operand_type[0]->immediate.resolved == 1)
+ {
+ /* Immediate addressing uses upper 8 bits of address. */
+ if (insn.operand_type[0]->immediate.u_number > 0x00FFFFFF)
+ {
+ as_bad (_("LDP instruction needs a 24-bit operand"));
+ return;
+ }
+ insn.opcode |=
+ ((insn.operand_type[0]->immediate.u_number & 0x00FF0000) >> 16);
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ }
+ else
+ {
+ fixS *fix;
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ fix = fix_new_exp (frag_now, p + 3 - (frag_now->fr_literal),
+ 1, &insn.operand_type[0]->immediate.imm_expr,
+ 0, 0);
+ fix->fx_no_overflow = 1;
+ }
+ }
+ }
+ else if (insn.tm->operand_types[0] & (Imm24))
+ {
+ /* Unconditional Branch and Call instructions. */
+ if (insn.operand_type[0]->immediate.resolved == 1)
+ {
+ if (insn.operand_type[0]->immediate.u_number > 0x00FFFFFF)
+ as_warn (_("first operand is too large for a 24-bit displacement"));
+ insn.opcode |=
+ (insn.operand_type[0]->immediate.u_number & 0x00FFFFFF);
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ }
+ else
+ {
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ fix_new_exp (frag_now, p + 1 - (frag_now->fr_literal), 3,
+ & insn.operand_type[0]->immediate.imm_expr, 0, 0);
+ }
+ }
+ else if (insn.tm->operand_types[0] & NotReq)
+ /* Check for NOP instruction without arguments. */
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+
+ else if (insn.tm->operands == 0)
+ /* Check for instructions without operands. */
+ md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE);
+ }
+ debug ("Addressing mode: %08X\n", insn.addressing_mode);
+ {
+ unsigned int i;
+
+ for (i = 0; i < insn.operands; i++)
+ {
+ if (insn.operand_type[i]->immediate.label)
+ free (insn.operand_type[i]->immediate.label);
+ free (insn.operand_type[i]);
+ }
+ }
+ debug ("Final opcode: %08X\n", insn.opcode);
+ debug ("\n");