📄 tc-tic30.c
字号:
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); { 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");}struct tic30_par_insn { partemplate *tm; /* Template of current parallel instruction */ int operands[2]; /* Number of given operands for each insn */ /* Type of operand given in instruction */ operand *operand_type[2][MAX_OPERANDS]; int swap_operands; /* Whether to swap operands around. */ unsigned p_field; /* Value of p field in multiply add/sub instructions */ unsigned opcode; /* Final opcode */};struct tic30_par_insn p_insn;inttic30_parallel_insn (char *token){ static partemplate *p_opcode; char *current_posn = token; char *token_start; char save_char; debug ("In tic30_parallel_insn with %s\n", token); memset (&p_insn, '\0', sizeof (p_insn)); while (is_opcode_char (*current_posn)) current_posn++; { /* Find instruction */ save_char = *current_posn; *current_posn = '\0'; p_opcode = (partemplate *) hash_find (parop_hash, token); if (p_opcode) { debug ("Found instruction %s\n", p_opcode->name); p_insn.tm = p_opcode; } else { char first_opcode[6] = {0}; char second_opcode[6] = {0}; int i; int current_opcode = -1; int char_ptr = 0; for (i = 0; i < strlen (token); i++) { char ch = *(token + i); if (ch == '_' && current_opcode == -1) { current_opcode = 0; continue; } if (ch == '_' && current_opcode == 0) { current_opcode = 1; char_ptr = 0; continue; } switch (current_opcode) { case 0: first_opcode[char_ptr++] = ch; break; case 1: second_opcode[char_ptr++] = ch; break; } } debug ("first_opcode = %s\n", first_opcode); debug ("second_opcode = %s\n", second_opcode); sprintf (token, "q_%s_%s", second_opcode, first_opcode); p_opcode = (partemplate *) hash_find (parop_hash, token); if (p_opcode) { debug ("Found instruction %s\n", p_opcode->name); p_insn.tm = p_opcode; p_insn.swap_operands = 1; } else return 0; } *current_posn = save_char; } { /* Find operands */ int paren_not_balanced; int expecting_operand = 0; int found_separator = 0; do { /* skip optional white space before operand */ while (!is_operand_char (*current_posn) && *current_posn != END_OF_INSN) { if (!is_space_char (*current_posn) && *current_posn != PARALLEL_SEPARATOR) { as_bad ("Invalid character %s before %s operand", output_invalid (*current_posn), ordinal_names[insn.operands]); return 1; } if (*current_posn == PARALLEL_SEPARATOR) found_separator = 1; current_posn++; } token_start = current_posn; /* after white space */ 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 1; } else break; /* we are done */ } else if (*current_posn == PARALLEL_SEPARATOR) { while (is_space_char (*(current_posn - 1))) current_posn--; 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 1; } if (*current_posn == '(') ++paren_not_balanced; if (*current_posn == ')') --paren_not_balanced; current_posn++; } if (current_posn != token_start)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -