📄 tc-cris.c
字号:
out_insnp->opcode = instruction->match; out_insnp->reloc = BFD_RELOC_NONE; out_insnp->insn_type = CRIS_INSN_NORMAL; out_insnp->imm_oprnd_size = 0; imm_expr_found = 0; /* Build the opcode, checking as we go to make sure that the operands match. */ for (args = instruction->args;; ++args) { switch (*args) { case '\0': /* If we've come to the end of arguments, we're done. */ if (*s == '\0') match = 1; break; case '!': /* Non-matcher character for disassembly. Ignore it here. */ continue; case ',': case ' ': /* These must match exactly. */ if (*s++ == *args) continue; break; case 'B': /* This is not really an operand, but causes a "BDAP -size,SP" prefix to be output, for PUSH instructions. */ prefixp->kind = PREFIX_PUSH; continue; case 'b': /* This letter marks an operand that should not be matched in the assembler. It is a branch with 16-bit displacement. The assembler will create them from the 8-bit flavor when necessary. The assembler does not support the [rN+] operand, as the [r15+] that is generated for 16-bit displacements. */ break; case 'c': /* A 5-bit unsigned immediate in bits <4:0>. */ if (! cris_get_expression (&s, &out_insnp->expr)) break; else { if (out_insnp->expr.X_op == O_constant && (out_insnp->expr.X_add_number < 0 || out_insnp->expr.X_add_number > 31)) as_bad (_("Immediate value not in 5 bit unsigned range: %ld"), out_insnp->expr.X_add_number); out_insnp->reloc = BFD_RELOC_CRIS_UNSIGNED_5; continue; } case 'C': /* A 4-bit unsigned immediate in bits <3:0>. */ if (! cris_get_expression (&s, &out_insnp->expr)) break; else { if (out_insnp->expr.X_op == O_constant && (out_insnp->expr.X_add_number < 0 || out_insnp->expr.X_add_number > 15)) as_bad (_("Immediate value not in 4 bit unsigned range: %ld"), out_insnp->expr.X_add_number); out_insnp->reloc = BFD_RELOC_CRIS_UNSIGNED_4; continue; } case 'D': /* General register in bits <15:12> and <3:0>. */ if (! get_gen_reg (&s, ®no)) break; else { out_insnp->opcode |= regno /* << 0 */; out_insnp->opcode |= regno << 12; continue; } case 'f': /* Flags from the condition code register. */ { int flags = 0; if (! get_flags (&s, &flags)) break; out_insnp->opcode |= ((flags & 0xf0) << 8) | (flags & 0xf); continue; } case 'i': /* A 6-bit signed immediate in bits <5:0>. */ if (! cris_get_expression (&s, &out_insnp->expr)) break; else { if (out_insnp->expr.X_op == O_constant && (out_insnp->expr.X_add_number < -32 || out_insnp->expr.X_add_number > 31)) as_bad (_("Immediate value not in 6 bit range: %ld"), out_insnp->expr.X_add_number); out_insnp->reloc = BFD_RELOC_CRIS_SIGNED_6; continue; } case 'I': /* A 6-bit unsigned immediate in bits <5:0>. */ if (! cris_get_expression (&s, &out_insnp->expr)) break; else { if (out_insnp->expr.X_op == O_constant && (out_insnp->expr.X_add_number < 0 || out_insnp->expr.X_add_number > 63)) as_bad (_("Immediate value not in 6 bit unsigned range: %ld"), out_insnp->expr.X_add_number); out_insnp->reloc = BFD_RELOC_CRIS_UNSIGNED_6; continue; } case 'M': /* A size modifier, B, W or D, to be put in a bit position suitable for CLEAR instructions (i.e. reflecting a zero register). */ if (! get_bwd_size_modifier (&s, &size_bits)) break; else { switch (size_bits) { case 0: out_insnp->opcode |= 0 << 12; break; case 1: out_insnp->opcode |= 4 << 12; break; case 2: out_insnp->opcode |= 8 << 12; break; } continue; } case 'm': /* A size modifier, B, W or D, to be put in bits <5:4>. */ if (! get_bwd_size_modifier (&s, &size_bits)) break; else { out_insnp->opcode |= size_bits << 4; continue; } case 'o': /* A branch expression. */ if (! cris_get_expression (&s, &out_insnp->expr)) break; else { out_insnp->insn_type = CRIS_INSN_BRANCH; continue; } case 'O': /* A BDAP expression for any size, "expr,r". */ if (! cris_get_expression (&s, &prefixp->expr)) break; else { if (*s != ',') break; s++; if (!get_gen_reg (&s, &prefixp->base_reg_number)) break; /* Since 'O' is used with an explicit bdap, we have no "real" instruction. */ prefixp->kind = PREFIX_BDAP_IMM; out_insnp->insn_type = CRIS_INSN_NONE; continue; } case 'P': /* Special register in bits <15:12>. */ if (! get_spec_reg (&s, &out_insnp->spec_reg)) break; else { /* Use of some special register names come with a specific warning. Note that we have no ".cpu type" pseudo yet, so some of this is just unused framework. */ if (out_insnp->spec_reg->warning) as_warn (out_insnp->spec_reg->warning); else if (out_insnp->spec_reg->applicable_version == cris_ver_warning) /* Others have a generic warning. */ as_warn (_("Unimplemented register `%s' specified"), out_insnp->spec_reg->name); out_insnp->opcode |= out_insnp->spec_reg->number << 12; continue; } case 'p': /* This character is used in the disassembler to recognize a prefix instruction to fold into the addressing mode for the next instruction. It is ignored here. */ continue; case 'R': /* General register in bits <15:12>. */ if (! get_gen_reg (&s, ®no)) break; else { out_insnp->opcode |= regno << 12; continue; } case 'r': /* General register in bits <3:0>. */ if (! get_gen_reg (&s, ®no)) break; else { out_insnp->opcode |= regno /* << 0 */; continue; } case 'S': /* Source operand in bit <10> and a prefix; a 3-operand prefix. */ if (! get_3op_or_dip_prefix_op (&s, prefixp)) break; else continue; case 's': /* Source operand in bits <10>, <3:0> and optionally a prefix; i.e. an indirect operand or an side-effect prefix. */ if (! get_autoinc_prefix_or_indir_op (&s, prefixp, &mode, ®no, &imm_expr_found, &out_insnp->expr)) break; else { if (prefixp->kind != PREFIX_NONE) { /* A prefix, so it has the autoincrement bit set. */ out_insnp->opcode |= (AUTOINCR_BIT << 8); } else /* No prefix. The "mode" variable contains bits like whether or not this is autoincrement mode. */ out_insnp->opcode |= (mode << 10); out_insnp->opcode |= regno /* << 0 */ ; continue; } case 'x': /* Rs.m in bits <15:12> and <5:4>. */ if (! get_gen_reg (&s, ®no) || ! get_bwd_size_modifier (&s, &size_bits)) break; else { out_insnp->opcode |= (regno << 12) | (size_bits << 4); continue; } case 'y': /* Source operand in bits <10>, <3:0> and optionally a prefix; i.e. an indirect operand or an side-effect prefix. The difference to 's' is that this does not allow an "immediate" expression. */ if (! get_autoinc_prefix_or_indir_op (&s, prefixp, &mode, ®no, &imm_expr_found, &out_insnp->expr) || imm_expr_found) break; else { if (prefixp->kind != PREFIX_NONE) { /* A prefix, and those matched here always have side-effects (see 's' case). */ out_insnp->opcode |= (AUTOINCR_BIT << 8); } else { /* No prefix. The "mode" variable contains bits like whether or not this is autoincrement mode. */ out_insnp->opcode |= (mode << 10); } out_insnp->opcode |= regno /* << 0 */; continue; } case 'z': /* Size modifier (B or W) in bit <4>. */ if (! get_bw_size_modifier (&s, &size_bits)) break; else { out_insnp->opcode |= size_bits << 4; continue; } default: BAD_CASE (*args); } /* We get here when we fail a match above or we found a complete match. Break out of this loop. */ break; } /* Was it a match or a miss? */ if (match == 0) { /* If it's just that the args don't match, maybe the next item in the table is the same opcode but with matching operands. */ if (instruction[1].name != NULL && ! strcmp (instruction->name, instruction[1].name)) { /* Yep. Restart and try that one instead. */ ++instruction; s = operands; continue; } else { /* We've come to the end of instructions with this opcode, so it must be an error. */ as_bad (_("Illegal operands")); return; } } else { /* We have a match. Check if there's anything more to do. */ if (imm_expr_found) { /* There was an immediate mode operand, so we must check that it has an appropriate size. */ switch (instruction->imm_oprnd_size) { default: case SIZE_NONE: /* Shouldn't happen; this one does not have immediate operands with different sizes. */ BAD_CASE (instruction->imm_oprnd_size); break; case SIZE_FIX_32: out_insnp->imm_oprnd_size = 4; break; case SIZE_SPEC_REG: switch (out_insnp->spec_reg->reg_size) { case 1: if (out_insnp->expr.X_op == O_constant && (out_insnp->expr.X_add_number < -128 || out_insnp->expr.X_add_number > 255)) as_bad (_("Immediate value not in 8 bit range: %ld"), out_insnp->expr.X_add_number); /* Fall through. */ case 2: /* FIXME: We need an indicator in the instruction table to pass on, to indicate if we need to check overflow for a signed or unsigned number. */ if (out_insnp->expr.X_op == O_constant && (out_insnp->expr.X_add_number < -32768 || out_insnp->expr.X_add_number > 65535)) as_bad (_("Immediate value not in 16 bit range: %ld"), out_insnp->expr.X_add_number); out_insnp->imm_oprnd_size = 2; break; case 4: out_insnp->imm_oprnd_size = 4; break; default: BAD_CASE (out_insnp->spec_reg->reg_size); } break; case SIZE_FIELD: switch (size_bits) { case 0: if (out_insnp->expr.X_op == O_constant && (out_insnp->expr.X_add_number < -128 || out_insnp->expr.X_add_number > 255)) as_bad (_("Immediate value not in 8 bit range: %ld"), out_insnp->expr.X_add_number); /* Fall through. */ case 1: if (out_insnp->expr.X_op == O_constant && (out_insnp->expr.X_add_number < -32768 || out_insnp->expr.X_add_number > 65535)) as_bad (_("Immediate value not in 16 bit range: %ld"), out_insnp->expr.X_add_number); out_insnp->imm_oprnd_size = 2; break; case 2: out_insnp->imm_oprnd_size = 4; break; default: BAD_CASE (out_insnp->spec_reg->reg_size); } } } } break; }}/* Get a B, W, or D size modifier from the string pointed out by *cPP, which must point to a '.' in front of the modifier. On successful return, *cPP is advanced to the character following the size modifier, and is undefined otherwise. cPP Pointer to pointer to string starting with the size modifier. size_bitsp Pointer to variable to contain the size bits on successful return. Return 1 iff a correct size modifier is found, else 0. */static intget_bwd_size_modifier (cPP, size_bitsp) char **cPP; int *size_bitsp;{ if (**cPP != '.') return 0; else { /* Consume the '.'. */ (*cPP)++; switch (**cPP) { case 'B': case 'b':
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -