📄 tc-cris.c
字号:
/* We must have a '[' or it's a clean failure. */ return 0; /* Eat the first '['. */ (*cPP)++; if (**cPP == '[') { /* A second '[', so this must be double-indirect mode. */ (*cPP)++; prefixp->kind = PREFIX_DIP; prefixp->opcode = DIP_OPCODE; /* Get the register or fail entirely. */ if (! get_gen_reg (cPP, ®_number)) return 0; else { prefixp->opcode |= reg_number /* << 0 */ ; if (**cPP == '+') { /* Since we found a '+', this must be double-indirect autoincrement mode. */ (*cPP)++; prefixp->opcode |= AUTOINCR_BIT << 8; } /* There's nothing particular to do, if this was a double-indirect *without* autoincrement. */ } /* Check the first ']'. The second one is checked at the end. */ if (**cPP != ']') return 0; /* Eat the first ']', so we'll be looking at a second ']'. */ (*cPP)++; } /* No second '['. Then we should have a register here, making it "[rN". */ else if (get_gen_reg (cPP, &prefixp->base_reg_number)) { /* This must be indexed or offset mode: "[rN+I]" or "[rN+rM.S]" or "[rN+[rM].S]" or "[rN+[rM+].S]". */ if (**cPP == '+') { /* Not the first alternative, must be one of the last three. */ int index_reg_number; (*cPP)++; if (**cPP == '[') { /* This is "[rx+["... Expect a register next. */ int size_bits; (*cPP)++; if (!get_gen_reg (cPP, &index_reg_number)) return 0; prefixp->kind = PREFIX_BDAP; prefixp->opcode = (BDAP_INDIR_OPCODE + (prefixp->base_reg_number << 12) + index_reg_number); /* We've seen "[rx+[ry", so check if this is autoincrement. */ if (**cPP == '+') { /* Yep, now at "[rx+[ry+". */ (*cPP)++; prefixp->opcode |= AUTOINCR_BIT << 8; } /* If it wasn't autoincrement, we don't need to add anything. */ /* Check a first closing ']': "[rx+[ry]" or "[rx+[ry+]". */ if (**cPP != ']') return 0; (*cPP)++; /* Now expect a size modifier ".S". */ if (! get_bwd_size_modifier (cPP, &size_bits)) return 0; prefixp->opcode |= size_bits << 4; /* Ok, all interesting stuff has been seen: "[rx+[ry+].S" or "[rx+[ry].S". We only need to expect a final ']', which we'll do in a common closing session. */ } /* Seen "[rN+", but not a '[', so check if we have a register. */ else if (get_gen_reg (cPP, &index_reg_number)) { /* This is indexed mode: "[rN+rM.S]" or "[rN+rM.S+]". */ int size_bits; prefixp->kind = PREFIX_BIAP; prefixp->opcode = (BIAP_OPCODE | prefixp->base_reg_number /* << 0 */ | (index_reg_number << 12)); /* Consume the ".S". */ if (! get_bwd_size_modifier (cPP, &size_bits)) /* Missing size, so fail. */ return 0; else /* Size found. Add that piece and drop down to the common checking of the closing ']'. */ prefixp->opcode |= size_bits << 4; } /* Seen "[rN+", but not a '[' or a register, so then it must be a constant "I". */ else if (cris_get_expression (cPP, &prefixp->expr)) { /* Expression found, so fill in the bits of offset mode and drop down to check the closing ']'. */ prefixp->kind = PREFIX_BDAP_IMM; } else /* Nothing valid here: lose. */ return 0; } /* Seen "[rN" but no '+', so check if it's a '-'. */ else if (**cPP == '-') { /* Yep, we must have offset mode. */ if (! cris_get_expression (cPP, &prefixp->expr)) /* No expression, so we lose. */ return 0; else { /* Expression found to make this offset mode, so fill those bits and drop down to check the closing ']'. */ prefixp->kind = PREFIX_BDAP_IMM; } } else { /* We've seen "[rN", but not '+' or '-'; rather a ']'. Hmm. Normally this is a simple indirect mode that we shouldn't match, but if we expect ']', then we have a zero offset, so it can be a three-address-operand, like "[rN],rO,rP", thus offset mode. Don't eat the ']', that will be done in the closing ceremony. */ prefixp->expr.X_op = O_constant; prefixp->expr.X_add_number = 0; prefixp->expr.X_add_symbol = NULL; prefixp->expr.X_op_symbol = NULL; prefixp->kind = PREFIX_BDAP_IMM; } } /* A '[', but no second '[', and no register. Check if we have an expression, making this "[I]" for a double-indirect prefix. */ else if (cris_get_expression (cPP, &prefixp->expr)) { /* Expression found, the so called absolute mode for a double-indirect prefix on PC. */ prefixp->kind = PREFIX_DIP; prefixp->opcode = DIP_OPCODE | (AUTOINCR_BIT << 8) | REG_PC; prefixp->reloc = BFD_RELOC_32; } else /* Neither '[' nor register nor expression. We lose. */ return 0; /* We get here as a closing ceremony to a successful match. We just need to check the closing ']'. */ if (**cPP != ']') /* Oops. Close but no air-polluter. */ return 0; /* Don't forget to consume that ']', before returning in glory. */ (*cPP)++; return 1;}/* Get an expression from the string pointed out by *cPP. The pointer *cPP is advanced to the character following the expression on a success, or retains its original value otherwise. cPP Pointer to pointer to string beginning with the expression. exprP Pointer to structure containing the expression. Return 1 iff a correct expression is found. */static intcris_get_expression (cPP, exprP) char **cPP; expressionS *exprP;{ char *saved_input_line_pointer; segT exp; /* The "expression" function expects to find an expression at the global variable input_line_pointer, so we have to save it to give the impression that we don't fiddle with global variables. */ saved_input_line_pointer = input_line_pointer; input_line_pointer = *cPP; exp = expression (exprP); if (exprP->X_op == O_illegal || exprP->X_op == O_absent) { input_line_pointer = saved_input_line_pointer; return 0; } /* Everything seems to be fine, just restore the global input_line_pointer and say we're successful. */ *cPP = input_line_pointer; input_line_pointer = saved_input_line_pointer; return 1;}/* Get a sequence of flag characters from *spp. The pointer *cPP is advanced to the character following the expression. The flag characters are consecutive, no commas or spaces. cPP Pointer to pointer to string beginning with the expression. flagp Pointer to int to return the flags expression. Return 1 iff a correct flags expression is found. */static intget_flags (cPP, flagsp) char **cPP; int *flagsp;{ for (;;) { switch (**cPP) { case 'd': case 'D': case 'm': case 'M': *flagsp |= 0x80; break; case 'e': case 'E': case 'b': case 'B': *flagsp |= 0x40; break; case 'i': case 'I': *flagsp |= 0x20; break; case 'x': case 'X': *flagsp |= 0x10; break; case 'n': case 'N': *flagsp |= 0x8; break; case 'z': case 'Z': *flagsp |= 0x4; break; case 'v': case 'V': *flagsp |= 0x2; break; case 'c': case 'C': *flagsp |= 1; break; default: /* We consider this successful if we stop at a comma or whitespace. Anything else, and we consider it a failure. */ if (**cPP != ',' && **cPP != 0 && ! isspace (**cPP)) return 0; else return 1; } /* Don't forget to consume each flag character. */ (*cPP)++; }}/* Generate code and fixes for a BDAP prefix. base_regno Int containing the base register number. exprP Pointer to structure containing the offset expression. */static voidgen_bdap (base_regno, exprP) int base_regno; expressionS *exprP;{ unsigned int opcode; char *opcodep; /* Put out the prefix opcode; assume quick immediate mode at first. */ opcode = BDAP_QUICK_OPCODE | (base_regno << 12); opcodep = cris_insn_first_word_frag (); md_number_to_chars (opcodep, opcode, 2); if (exprP->X_op == O_constant) { /* We have an absolute expression that we know the size of right now. */ long int value; int size; value = exprP->X_add_number; if (value < -32768 || value > 32767) /* Outside range for a "word", make it a dword. */ size = 2; else /* Assume "word" size. */ size = 1; /* If this is a signed-byte value, we can fit it into the prefix insn itself. */ if (value >= -128 && value <= 127) opcodep[0] = value; else { /* This is a word or dword displacement, which will be put in a word or dword after the prefix. */ char *p; opcodep[0] = BDAP_PC_LOW + (size << 4); opcodep[1] &= 0xF0; opcodep[1] |= BDAP_INCR_HIGH; p = frag_more (1 << size); md_number_to_chars (p, value, 1 << size); } } else /* The expression is not defined yet but may become absolute. We make it a relocation to be relaxed. */ frag_var (rs_machine_dependent, 4, 0, ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_UNDF), exprP->X_add_symbol, exprP->X_add_number, opcodep);}/* Encode a branch displacement in the range -256..254 into the form used by CRIS conditional branch instructions. offset The displacement value in bytes. */static intbranch_disp (offset) int offset;{ int disp; disp = offset & 0xFE; if (offset < 0) disp |= 1; return disp;}/* Generate code and fixes for a 32-bit conditional branch instruction created by "extending" an existing 8-bit branch instruction. opcodep Pointer to the word containing the original 8-bit branch instruction. writep Pointer to "extension area" following the first instruction word. fragP Pointer to the frag containing the instruction. add_symP, Parts of the destination address expression. sub_symP, add_num. */static voidgen_cond_branch_32 (opcodep, writep, fragP, add_symP, sub_symP, add_num) char *opcodep; char *writep; fragS *fragP; symbolS *add_symP; symbolS *sub_symP; long int add_num;{ if (warn_for_branch_expansion) { /* FIXME: Find out and change to as_warn_where. Add testcase. */ as_warn (_("32-bit conditional branch generated")); } /* Here, writep points to what will be opcodep + 2. First, we change the actual branch in opcodep[0] and opcodep[1], so that in the final insn, it will look like: opcodep+10: Bcc .-6 This means we don't have to worry about changing the opcode or messing with te delay-slot instruction. So, we move it to last in the "extended" branch, and just change the displacement. Admittedly, it's not the optimal extended construct, but we should get this rarely enough that it shouldn't matter. */ writep[8] = branch_disp (-2 - 6); writep[9] = opcodep[1]; /* Then, we change the branch to an unconditional branch over the extended part, to the new location of the Bcc: opcodep: BA .+10 opcodep+2: NOP Note that these two writes are to currently different locations, merged later. */ md_number_to_chars (opcodep, BA_QUICK_OPCODE + 8, 2); md_number_to_chars (writep, NOP_OPCODE, 2); /* Then the extended thing, the 32-bit jump insn. opcodep+4: JUMP [PC+] */ md_number_to_chars (writep + 2, JUMP_PC_INCR_OPCODE, 2); /* We have to fill in the actual value too. opcodep+6: .DWORD This is most probably an expression, but we can cope with an absolute value too. FIXME: Testcase needed. */ if (add_symP == NULL && sub_symP == NULL) /* An absolute address. */ md_number_to_chars (writep + 4, add_num, 4); else { /* Not absolute, we have to make it a frag for later evaluation. */ know (sub_symP == 0); fix_new (fragP, writep + 4 - fragP->fr_literal, 4, add_symP, add_num, 0, BFD_RELOC_32); }}/* This *could* be: Turn a string in input_line_pointer into a floating point constant of type TYPE, and store the appropriate bytes in *LITP. The number of LITTLENUMS emitted is stored in *SIZEP. type A character from FLTCHARS that describes what kind of floating-point number is wanted. litp A pointer to an array that the result should be stored in. sizep A pointer to an integer where the size of the result is stored. But we don't support floating point constants in assembly code *at all*, since it's suboptimal and just opens up bug opportunities. GCC emits the bit patterns as hex. All we could do here is to emit what GCC would have done in the first place. *Nobody* writes floating-point code a
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -