+ int expi; /* Index of current expression to match */
+ int opi; /* Index of current operand to match */
+ unsigned long insn[2]; /* Instruction and long immediate (if any) */
+ int extended = 0; /* Nonzero if instruction is 8 bytes */
+ char *f; /* Temporary pointer to output location */
+
+ /* Start with the raw opcode bits from the opcode table. */
+ insn[0] = opcode -> opcode;
+
+ /* For each operand expression, insert the appropriate bits into the
+ instruction . */
+ for (expi = 0, opi = -1; opers[expi].X_op != O_illegal; expi++)
+ {
+ int bits, shift, flags, X_op, num;
+
+ X_op = opers[expi].X_op;
+ num = opers[expi].X_add_number;
+ if (X_op != O_absent)
+ {
+ /* The O_absent expressions apply to the previously seen
+ operand, so only increment the operand index when the
+ current expression needs to be matched against the next
+ operand. */
+ opi++;
+ }
+ else
+ {
+ /* Found a modifier that applies to the previously
+ seen operand, so handle it. */
+ switch (opers[expi].X_add_number)
+ {
+ case TIC80_OPERAND_M_SI | TIC80_OPERAND_M_LI:
+ internal_error_a ("unhandled operand modifier", opers[expi].X_add_number);
+ break;
+ case TIC80_OPERAND_SCALED:
+ internal_error_a ("unhandled operand modifier", opers[expi].X_add_number);
+ break;
+ case TIC80_OPERAND_PARENS:
+ internal_error_a ("unhandled operand modifier", opers[expi].X_add_number);
+ break;
+ default:
+ internal_error_a ("unhandled operand modifier", opers[expi].X_add_number);
+ break;
+ }
+ }
+ flags = tic80_operands[opcode -> operands[opi]].flags;
+ bits = tic80_operands[opcode -> operands[opi]].bits;
+ shift = tic80_operands[opcode -> operands[opi]].shift;
+
+ switch (X_op)
+ {
+ case O_register:
+ num &= ~TIC80_OPERAND_MASK;
+ insn[0] = insn[0] | (num << shift);
+ break;
+ case O_constant:
+ if ((flags & TIC80_OPERAND_ENDMASK) && (num == 32))
+ {
+ /* Endmask values of 0 and 32 give identical results */
+ num = 0;
+ }
+ /* Mask off upper bits, just it case it is signed and is negative */
+ if (bits < 32)
+ {
+ num &= (1 << bits) - 1;
+ insn[0] = insn[0] | (num << shift);
+ }
+ else
+ {
+ extended++;
+ insn[1] = num;
+ }
+ break;
+ case O_illegal:
+ case O_absent:
+ case O_symbol:
+ case O_symbol_rva:
+ case O_big:
+ case O_uminus:
+ case O_bit_not:
+ case O_logical_not:
+ case O_multiply:
+ case O_divide:
+ case O_modulus:
+ case O_left_shift:
+ case O_right_shift:
+ case O_bit_inclusive_or:
+ case O_bit_or_not:
+ case O_bit_exclusive_or:
+ case O_bit_and:
+ case O_add:
+ case O_subtract:
+ case O_eq:
+ case O_ne:
+ case O_lt:
+ case O_le:
+ case O_ge:
+ case O_gt:
+ case O_logical_and:
+ case O_logical_or:
+ case O_max:
+ default:
+ internal_error_a ("unhandled expression", X_op);
+ break;
+ }
+ }
+
+ /* Write out the instruction, either 4 or 8 bytes. */
+
+ f = frag_more (4);
+ md_number_to_chars (f, insn[0], 4);
+ if (extended)
+ {
+ f = frag_more (4);
+ md_number_to_chars (f, insn[1], 4);
+ }