📄 vax.c
字号:
int length; /* length (bytes) meant by vop_short. */ int at; /* 0, or 1 if '@' is in addressing mode. */ int nbytes; /* From vop_nbytes: vax_operand_width (in bytes) */ FLONUM_TYPE *floatP; char *vip (); LITTLENUM_TYPE literal_float[8]; /* Big enough for any floating point literal. */ if (*(p = vip (&v, instruction_string))) { as_fatal ("vax_assemble\"%s\" in=\"%s\"", p, instruction_string); } /* * Now we try to find as many as_warn()s as we can. If we do any as_warn()s * then goofed=TRUE. Notice that we don't make any frags yet. * Should goofed be TRUE, then this instruction will wedge in any pass, * and we can safely flush it, without causing interpass symbol phase * errors. That is, without changing label values in different passes. */ if (goofed = (*v.vit_error)) { as_warn ("Ignoring statement due to \"%s\"", v.vit_error); } /* * We need to use expression() and friends, which require us to diddle * input_line_pointer. So we save it and restore it later. */ save_input_line_pointer = input_line_pointer; for (operandP = v.vit_operand, expP = exp_of_operand, floatP = float_operand, end_operandP = v.vit_operand + v.vit_operands; operandP < end_operandP; operandP++, expP++, floatP++ ) /* for each operand */ { if (*(operandP->vop_error)) { as_warn ("Ignoring statement because \"%s\"", (operandP->vop_error)); goofed = TRUE; } else { /* statement has no syntax goofs: lets sniff the expression */ int can_be_short; /* TRUE if a bignum can be reduced to a short literal. */ input_line_pointer = operandP->vop_expr_begin; c_save = operandP->vop_expr_end[1]; operandP->vop_expr_end[1] = '\0'; /* If to_seg == SEG_PASS1, expression() will have set need_pass_2 = TRUE. */ switch (to_seg = expression (expP)) { case SEG_NONE: /* for BSD4.2 compatibility, missing expression is absolute 0 */ to_seg = expP->X_seg = SEG_ABSOLUTE; expP->X_add_number = 0; /* for SEG_ABSOLUTE, we shouldnt need to set X_subtract_symbol, X_add_symbol to any particular value. */ /* But, we will program defensively. Since this situation occurs */ /* rarely so it costs us little to do, and stops Dean */ /* worrying about the origin of random bits in expressionS's. */ expP->X_add_symbol = NULL; expP->X_subtract_symbol = NULL; case SEG_TEXT: case SEG_DATA: case SEG_BSS: case SEG_ABSOLUTE: case SEG_UNKNOWN: break; case SEG_DIFFERENCE: case SEG_PASS1: /* * Major bug. We can't handle the case of a * SEG_DIFFERENCE expression in a VIT_OPCODE_SYNTHETIC * variable-length instruction. * We don't have a frag type that is smart enough to * relax a SEG_DIFFERENCE, and so we just force all * SEG_DIFFERENCEs to behave like SEG_PASS1s. * Clearly, if there is a demand we can invent a new or * modified frag type and then coding up a frag for this * case will be easy. SEG_DIFFERENCE was invented for the * .words after a CASE opcode, and was never intended for * instruction operands. */ need_pass_2 = TRUE; as_warn("Can't relocate expression"); break; case SEG_BIG: /* Preserve the bits. */ if (expP->X_add_number > 0) { bignum_copy (generic_bignum, expP->X_add_number, floatP->low, SIZE_OF_LARGE_NUMBER); } else { know (expP->X_add_number < 0); flonum_copy (&generic_floating_point_number, floatP); if (index ("s i", operandP->vop_short)) { /* Could possibly become S^# */ flonum_gen2vax (-expP->X_add_number, floatP, literal_float); switch (-expP->X_add_number) { case 'f': can_be_short = (literal_float[0] & 0xFC0F) == 0x4000 && literal_float[1] == 0; break; case 'd': can_be_short = (literal_float[0] & 0xFC0F) == 0x4000 && literal_float[1] == 0 && literal_float[2] == 0 && literal_float[3] == 0; break; case 'g': can_be_short = (literal_float[0] & 0xFF81) == 0x4000 && literal_float[1] == 0 && literal_float[2] == 0 && literal_float[3] == 0; break; case 'h': can_be_short = (literal_float[0] & 0xFFF8) == 0x4000 && (literal_float[1] & 0xE000) == 0 && literal_float[2] == 0 && literal_float[3] == 0 && literal_float[4] == 0 && literal_float[5] == 0 && literal_float[6] == 0 && literal_float[7] == 0; break; default: BAD_CASE (-expP->X_add_number); break; } /* switch (float type) */ } /* if (could want to become S^#...) */ } /* bignum or flonum ? */ if (operandP->vop_short == 's' || operandP->vop_short == 'i' || (operandP->vop_short == ' ' && operandP->vop_reg == 0xF && (operandP->vop_mode & 0xE) == 0x8)) { /* Saw a '#'. */ if (operandP->vop_short == ' ') { /* We must chose S^ or I^. */ if (expP->X_add_number > 0) { /* Bignum: Short literal impossible. */ operandP->vop_short = 'i'; operandP->vop_mode = 8; operandP->vop_reg = 0xF; /* VAX PC. */ } else { /* Flonum: Try to do it. */ if (can_be_short) { operandP->vop_short = 's'; operandP->vop_mode = 0; operandP->vop_ndx = -1; operandP->vop_reg = -1; /* JF hope this is the right thing */ expP->X_seg = SEG_ABSOLUTE; } else { operandP->vop_short = 'i'; operandP->vop_mode = 8; operandP->vop_reg = 0xF; /* VAX PC */ } } /* bignum or flonum ? */ } /* if #, but no S^ or I^ seen. */ /* No more ' ' case: either 's' or 'i'. */ if (operandP->vop_short == 's') { /* Wants to be a short literal. */ if (expP->X_add_number > 0) { as_warn ("Bignum not permitted in short literal. Immediate mode assumed."); operandP->vop_short = 'i'; operandP->vop_mode = 8; operandP->vop_reg = 0xF; /* VAX PC. */ } else { if (!can_be_short) { as_warn ("Can't do flonum short literal: immediate mode used."); operandP->vop_short = 'i'; operandP->vop_mode = 8; operandP->vop_reg = 0xF; /* VAX PC. */ } else { /* Encode short literal now. */ register int temp; switch (-expP->X_add_number) { case 'f': case 'd': temp = literal_float[0] >> 4; break; case 'g': temp = literal_float[0] >> 1; break; case 'h': temp = ((literal_float[0] << 3) & 070) | ((literal_float[1] >> 13) & 07); break; default: BAD_CASE (-expP->X_add_number); break; } floatP->low[0] = temp & 077; floatP->low[1] = 0; } /* if can be short literal float */ } /* flonum or bignum ? */ } else { /* I^# seen: set it up if float. */ if (expP->X_add_number < 0) { bcopy (literal_float, floatP->low, sizeof (literal_float)); } } /* if S^# seen. */ } else { as_warn ("A bignum/flonum may not be a displacement: 0x%x used", expP->X_add_number = 0x80000000); /* Chosen so luser gets the most offset bits to patch later. */ } expP->X_add_number = floatP->low[0] | ((LITTLENUM_MASK & (floatP->low[1])) << LITTLENUM_NUMBER_OF_BITS);/* * For the SEG_BIG case we have: * If vop_short == 's' then a short floating literal is in the * lowest 6 bits of floatP -> low [0], which is * big_operand_bits [---] [0]. * If vop_short == 'i' then the appropriate number of elements * of big_operand_bits [---] [...] are set up with the correct * bits. * Also, just in case width is byte word or long, we copy the lowest * 32 bits of the number to X_add_number. */ break; default: BAD_CASE (to_seg); break; } if (input_line_pointer != operandP->vop_expr_end + 1) { as_warn ("Junk at end of expression \"%s\"", input_line_pointer); goofed = TRUE; } operandP->vop_expr_end[1] = c_save; } } /* for(each operand) */ input_line_pointer = save_input_line_pointer; if (!need_pass_2 && !goofed) { /* We saw no errors in any operands - try to make frag(s) */ int is_undefined; /* True if operand expression's */ /* segment not known yet. */ int length_code; /* Emit op-code. */ /* Remember where it is, in case we want to modify the op-code later. */ opcode_low_byteP = frag_more (v.vit_opcode_nbytes); bcopy (v.vit_opcode, opcode_low_byteP, v.vit_opcode_nbytes); opcode_as_number = md_chars_to_number (opcode_as_chars = v.vit_opcode, 4); for (operandP = v.vit_operand, expP = exp_of_operand, floatP = float_operand, end_operandP = v.vit_operand + v.vit_operands; operandP < end_operandP; operandP++, floatP++, expP++ ) /* for each operand */ { if (operandP->vop_ndx >= 0) { /* indexed addressing byte */ /* Legality of indexed mode already checked: it is OK */ FRAG_APPEND_1_CHAR (0x40 + operandP->vop_ndx); } /* if(vop_ndx>=0) */ /* Here to make main operand frag(s). */ this_add_number = expP->X_add_number; this_add_symbol = expP->X_add_symbol; this_subtract_symbol = expP->X_subtract_symbol; to_seg = expP->X_seg; is_undefined = (to_seg == SEG_UNKNOWN); know (to_seg == SEG_UNKNOWN \ ||to_seg == SEG_ABSOLUTE \ ||to_seg == SEG_DATA \ ||to_seg == SEG_TEXT \ ||to_seg == SEG_BSS \ ||to_seg == SEG_BIG \ ); at = operandP->vop_mode & 1; length = operandP->vop_short == 'b' ? 1 : operandP->vop_short == 'w' ? 2 : operandP->vop_short == 'l' ? 4 : 0; nbytes = operandP->vop_nbytes; if (operandP->vop_access == 'b') { if (to_seg == now_seg || is_undefined) { /* If is_undefined, then it might BECOME now_seg. */ if (nbytes) { p = frag_more (nbytes); fix_new (frag_now, p - frag_now->fr_literal, nbytes, this_add_symbol, 0, this_add_number, 1); } else { /* to_seg==now_seg || to_seg == SEG_UNKNOWN */ /* nbytes==0 */ length_code = is_undefined ? STATE_UNDF : STATE_BYTE; if (opcode_as_number & VIT_OPCODE_SPECIAL) { if (operandP->vop_width == VAX_WIDTH_UNCONDITIONAL_JUMP) { /* br or jsb */ frag_var (rs_machine_dependent, 5, 1, ENCODE_RELAX (STATE_ALWAYS_BRANCH, length_code), this_add_symbol, this_add_number, opcode_low_byteP); } else { if (operandP->vop_width == VAX_WIDTH_WORD_JUMP) { length_code = STATE_WORD; /* JF: There is no state_byte for this one! */ frag_var (rs_machine_dependent, 10, 2, ENCODE_RELAX (STATE_COMPLEX_BRANCH, length_code), this_add_symbol, this_add_number, opcode_low_byteP); } else { know (operandP->vop_width == VAX_WIDTH_BYTE_JUMP); frag_var (rs_machine_dependent, 9, 1, ENCODE_RELAX (STATE_COMPLEX_HOP, length_code), this_add_symbol, this_add_number, opcode_low_byteP); } } } else { know (operandP->vop_width == VAX_WIDTH_CONDITIONAL_JUMP); frag_var (rs_machine_dependent, 7, 1, ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, length_code), this_add_symbol, this_add_number, opcode_low_byteP); } } } else { /* to_seg != now_seg && to_seg != SEG_UNKNOWN *//* * --- SEG FLOAT MAY APPEAR HERE ---- */ if (to_seg == SEG_ABSOLUTE) { if (nbytes) { know (!(opcode_as_number & VIT_OPCODE_SYNTHETIC)); p = frag_more (nbytes); /* Conventional relocation. */ fix_new (frag_now, p - frag_now->fr_literal, nbytes, &abs_symbol, 0, this_add_number, 1); } else { know (opcode_as_number & VIT_OPCODE_SYNTHETIC); if (opcode_as_number & VIT_OPCODE_SPECIAL) { if (operandP->vop_width == VAX_WIDTH_UNCONDITIONAL_JUMP) { /* br or jsb */ *opcode_low_byteP = opcode_as_chars[0] + VAX_WIDEN_LONG; know (opcode_as_chars[1] == 0); p = frag_more (5); p[0] = VAX_ABSOLUTE_MODE; /* @#... */ md_number_to_chars (p + 1, this_add_number, 4); /* Now (eg) JMP @#foo or JSB @#foo. */ } else { if (operandP->vop_width == VAX_WIDTH_WORD_JUMP) { p = frag_more (10); p[0] = 2; p[1] = 0; p[2] = VAX_BRB; p[3] = 6; p[4] = VAX_JMP; p[5] = VAX_ABSOLUTE_MODE; /* @#... */ md_number_to_chars (p + 6, this_add_number, 4); /* * Now (eg) ACBx 1f * BRB 2f * 1: JMP @#foo * 2: */ } else { know (operandP->vop_width == VAX_WIDTH_BYTE_JUMP); p = frag_more (9); p[0] = 2; p[1] = VAX_BRB; p[2] = 6; p[3] = VAX_JMP; p[4] = VAX_PC_RELATIVE_MODE + 1; /* @#... */ md_number_to_chars (p + 5, this_add_number, 4); /* * Now (eg) xOBxxx 1f * BRB 2f * 1: JMP @#foo * 2: */ } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -