📄 tc-avr.c
字号:
if (ex.X_add_number > max || ex.X_add_number < 0) as_bad (_("number must be less than %d"), max + 1); return ex.X_add_number;}/* Parse instruction operands. Return binary opcode. */static unsigned intavr_operands (opcode, line) struct avr_opcodes_s *opcode; char **line;{ char *op = opcode->constraints; unsigned int bin = opcode->bin_opcode; char *frag = frag_more (opcode->insn_size * 2); char *str = *line; int where = frag - frag_now->fr_literal; static unsigned int prev = 0; /* Previous opcode. */ /* Opcode have operands. */ if (*op) { unsigned int reg1 = 0; unsigned int reg2 = 0; int reg1_present = 0; int reg2_present = 0; /* Parse first operand. */ if (REGISTER_P (*op)) reg1_present = 1; reg1 = avr_operand (opcode, where, op, &str); ++op; /* Parse second operand. */ if (*op) { if (*op == ',') ++op; if (*op == '=') { reg2 = reg1; reg2_present = 1; } else { if (REGISTER_P (*op)) reg2_present = 1; str = skip_space (str); if (*str++ != ',') as_bad (_("`,' required")); str = skip_space (str); reg2 = avr_operand (opcode, where, op, &str); } if (reg1_present && reg2_present) reg2 = (reg2 & 0xf) | ((reg2 << 5) & 0x200); else if (reg2_present) reg2 <<= 4; } if (reg1_present) reg1 <<= 4; bin |= reg1 | reg2; } /* Detect undefined combinations (like ld r31,Z+). */ if (!avr_opt.all_opcodes && AVR_UNDEF_P (bin)) as_warn (_("undefined combination of operands")); if (opcode->insn_size == 2) { /* Warn if the previous opcode was cpse/sbic/sbis/sbrc/sbrs (AVR core bug, fixed in the newer devices). */ if (!(avr_opt.no_skip_bug || (avr_mcu->isa & AVR_ISA_MUL)) && AVR_SKIP_P (prev)) as_warn (_("skipping two-word instruction")); bfd_putl32 ((bfd_vma) bin, frag); } else bfd_putl16 ((bfd_vma) bin, frag); prev = bin; *line = str; return bin;}/* Parse one instruction operand. Return operand bitmask. Also fixups can be generated. */static unsigned intavr_operand (opcode, where, op, line) struct avr_opcodes_s *opcode; int where; char *op; char **line;{ expressionS op_expr; unsigned int op_mask = 0; char *str = skip_space (*line); switch (*op) { /* Any register operand. */ case 'w': case 'd': case 'r': case 'a': case 'v': if (*str == 'r' || *str == 'R') { char r_name[20]; str = extract_word (str, r_name, sizeof (r_name)); op_mask = 0xff; if (isdigit (r_name[1])) { if (r_name[2] == '\0') op_mask = r_name[1] - '0'; else if (r_name[1] != '0' && isdigit (r_name[2]) && r_name[3] == '\0') op_mask = (r_name[1] - '0') * 10 + r_name[2] - '0'; } } else { op_mask = avr_get_constant (str, 31); str = input_line_pointer; } if (op_mask <= 31) { switch (*op) { case 'a': if (op_mask < 16 || op_mask > 23) as_bad (_("register r16-r23 required")); op_mask -= 16; break; case 'd': if (op_mask < 16) as_bad (_("register number above 15 required")); op_mask -= 16; break; case 'v': if (op_mask & 1) as_bad (_("even register number required")); op_mask >>= 1; break; case 'w': if ((op_mask & 1) || op_mask < 24) as_bad (_("register r24, r26, r28 or r30 required")); op_mask = (op_mask - 24) >> 1; break; } break; } as_bad (_("register name or number from 0 to 31 required")); break; case 'e': { char c; if (*str == '-') { str = skip_space (str + 1); op_mask = 0x1002; } c = tolower (*str); if (c == 'x') op_mask |= 0x100c; else if (c == 'y') op_mask |= 0x8; else if (c != 'z') as_bad (_("pointer register (X, Y or Z) required")); str = skip_space (str + 1); if (*str == '+') { ++str; if (op_mask & 2) as_bad (_("cannot both predecrement and postincrement")); op_mask |= 0x1001; } /* avr1 can do "ld r,Z" and "st Z,r" but no other pointer registers, no predecrement, no postincrement. */ if (!avr_opt.all_opcodes && (op_mask & 0x100F) && !(avr_mcu->isa & AVR_ISA_SRAM)) as_bad (_("addressing mode not supported")); } break; case 'z': if (*str == '-') as_bad (_("can't predecrement")); if (! (*str == 'z' || *str == 'Z')) as_bad (_("pointer register Z required")); str = skip_space (str + 1); if (*str == '+') { ++str; op_mask |= 1; } break; case 'b': { char c = tolower (*str++); if (c == 'y') op_mask |= 0x8; else if (c != 'z') as_bad (_("pointer register (Y or Z) required")); str = skip_space (str); if (*str++ == '+') { unsigned int x; x = avr_get_constant (str, 63); str = input_line_pointer; op_mask |= (x & 7) | ((x & (3 << 3)) << 7) | ((x & (1 << 5)) << 8); } } break; case 'h': str = parse_exp (str, &op_expr); fix_new_exp (frag_now, where, opcode->insn_size * 2, &op_expr, false, BFD_RELOC_AVR_CALL); break; case 'L': str = parse_exp (str, &op_expr); fix_new_exp (frag_now, where, opcode->insn_size * 2, &op_expr, true, BFD_RELOC_AVR_13_PCREL); break; case 'l': str = parse_exp (str, &op_expr); fix_new_exp (frag_now, where, opcode->insn_size * 2, &op_expr, true, BFD_RELOC_AVR_7_PCREL); break; case 'i': str = parse_exp (str, &op_expr); fix_new_exp (frag_now, where + 2, opcode->insn_size * 2, &op_expr, false, BFD_RELOC_16); break; case 'M': { bfd_reloc_code_real_type r_type; input_line_pointer = str; r_type = avr_ldi_expression (&op_expr); str = input_line_pointer; fix_new_exp (frag_now, where, 3, &op_expr, false, r_type); } break; case 'n': { unsigned int x; x = ~avr_get_constant (str, 255); str = input_line_pointer; op_mask |= (x & 0xf) | ((x << 4) & 0xf00); } break; case 'K': { unsigned int x; x = avr_get_constant (str, 63); str = input_line_pointer; op_mask |= (x & 0xf) | ((x & 0x30) << 2); } break; case 'S': case 's': { unsigned int x; x = avr_get_constant (str, 7); str = input_line_pointer; if (*op == 'S') x <<= 4; op_mask |= x; } break; case 'P': { unsigned int x; x = avr_get_constant (str, 63); str = input_line_pointer; op_mask |= (x & 0xf) | ((x & 0x30) << 5); } break; case 'p': { unsigned int x; x = avr_get_constant (str, 31); str = input_line_pointer; op_mask |= x << 3; } break; case '?': break; default: as_bad (_("unknown constraint `%c'"), *op); } *line = str; return op_mask;}/* GAS will call this function for each section at the end of the assembly, to permit the CPU backend to adjust the alignment of a section. */valueTmd_section_align (seg, addr) asection *seg; valueT addr;{ int align = bfd_get_section_alignment (stdoutput, seg); return ((addr + (1 << align) - 1) & (-1 << align));}/* If you define this macro, it should return the offset between the address of a PC relative fixup and the position from which the PC relative adjustment should be made. On many processors, the base of a PC relative instruction is the next instruction, so this macro would return the length of an instruction. */longmd_pcrel_from_section (fixp, sec) fixS *fixp; segT sec;{ if (fixp->fx_addsy != (symbolS *) NULL && (!S_IS_DEFINED (fixp->fx_addsy) || (S_GET_SEGMENT (fixp->fx_addsy) != sec))) return 0; return fixp->fx_frag->fr_address + fixp->fx_where;}/* GAS will call this for each fixup. It should store the correct value in the object file. */intmd_apply_fix3 (fixp, valuep, seg) fixS *fixp; valueT *valuep; segT seg;{ unsigned char *where; unsigned long insn; long value; if (fixp->fx_addsy == (symbolS *) NULL) { value = *valuep; fixp->fx_done = 1; } else if (fixp->fx_pcrel) { segT s = S_GET_SEGMENT (fixp->fx_addsy); if (fixp->fx_addsy && (s == seg || s == absolute_section)) { value = S_GET_VALUE (fixp->fx_addsy) + *valuep; fixp->fx_done = 1; } else value = *valuep; } else { value = fixp->fx_offset; if (fixp->fx_subsy != (symbolS *) NULL) { if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section) { value -= S_GET_VALUE (fixp->fx_subsy); fixp->fx_done = 1; } else { /* We don't actually support subtracting a symbol. */ as_bad_where (fixp->fx_file, fixp->fx_line, _("expression too complex")); } } } switch (fixp->fx_r_type) { default: fixp->fx_no_overflow = 1; break; case BFD_RELOC_AVR_7_PCREL: case BFD_RELOC_AVR_13_PCREL: case BFD_RELOC_32: case BFD_RELOC_16: case BFD_RELOC_AVR_CALL: break; } if (fixp->fx_done)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -