📄 tc-z8k.c
字号:
} if (ptr == 0) return NULL; if (*ptr == ',') ptr++; get_operand (&ptr, operand + 1, 1); break; case 3: ptr++; get_operand (&ptr, operand + 0, 0); if (*ptr == ',') ptr++; get_operand (&ptr, operand + 1, 1); if (*ptr == ',') ptr++; get_operand (&ptr, operand + 2, 2); break; case 4: ptr++; get_operand (&ptr, operand + 0, 0); if (*ptr == ',') ptr++; get_operand (&ptr, operand + 1, 1); if (*ptr == ',') ptr++; get_operand (&ptr, operand + 2, 2); if (*ptr == ',') ptr++; get_cc_operand (&ptr, operand + 3, 3); break; default: abort (); } return ptr;}/* Passed a pointer to a list of opcodes which use different addressing modes. Return the opcode which matches the opcodes provided. */static opcode_entry_type *get_specific (opcode, operands) opcode_entry_type *opcode; op_type *operands;{ opcode_entry_type *this_try = opcode; int found = 0; unsigned int noperands = opcode->noperands; int this_index = opcode->idx; while (this_index == opcode->idx && !found) { unsigned int i; this_try = opcode++; for (i = 0; i < noperands; i++) { unsigned int mode = operands[i].mode; if ((mode & CLASS_MASK) != (this_try->arg_info[i] & CLASS_MASK)) { /* It could be an pc rel operand, if this is a da mode and we like disps, then insert it. */ if (mode == CLASS_DA && this_try->arg_info[i] == CLASS_DISP) { /* This is the case. */ operands[i].mode = CLASS_DISP; } else if (mode == CLASS_BA && this_try->arg_info[i]) { /* Can't think of a way to turn what we've been given into something that's OK. */ goto fail; } else if (this_try->arg_info[i] & CLASS_PR) { if (mode == CLASS_REG_LONG && segmented_mode) { /* OK. */ } else if (mode == CLASS_REG_WORD && !segmented_mode) { /* OK. */ } else goto fail; } else goto fail; } switch (mode & CLASS_MASK) { default: break; case CLASS_X: case CLASS_IR: case CLASS_BA: case CLASS_BX: case CLASS_DISP: case CLASS_REG: case CLASS_REG_WORD: case CLASS_REG_BYTE: case CLASS_REG_QUAD: case CLASS_REG_LONG: case CLASS_REGN0: reg[this_try->arg_info[i] & ARG_MASK] = operands[i].reg; break; } } found = 1; fail: ; } if (found) return this_try; else return 0;}#if 0 /* Not used. */static voidcheck_operand (operand, width, string) struct z8k_op *operand; unsigned int width; char *string;{ if (operand->exp.X_add_symbol == 0 && operand->exp.X_op_symbol == 0) { /* No symbol involved, let's look at offset, it's dangerous if any of the high bits are not 0 or ff's, find out by oring or anding with the width and seeing if the answer is 0 or all fs. */ if ((operand->exp.X_add_number & ~width) != 0 && (operand->exp.X_add_number | width) != (~0)) { as_warn (_("operand %s0x%x out of range."), string, operand->exp.X_add_number); } }}#endifstatic char buffer[20];static voidnewfix (ptr, type, operand) int ptr; int type; expressionS *operand;{ if (operand->X_add_symbol || operand->X_op_symbol || operand->X_add_number) { fix_new_exp (frag_now, ptr, 1, operand, 0, type); }}static char *apply_fix (ptr, type, operand, size) char *ptr; int type; expressionS *operand; int size;{ int n = operand->X_add_number; newfix ((ptr - buffer) / 2, type, operand); switch (size) { case 8: /* 8 nibbles == 32 bits. */ *ptr++ = n >> 28; *ptr++ = n >> 24; *ptr++ = n >> 20; *ptr++ = n >> 16; case 4: /* 4 nibbles == 16 bits. */ *ptr++ = n >> 12; *ptr++ = n >> 8; case 2: *ptr++ = n >> 4; case 1: *ptr++ = n >> 0; break; } return ptr;}/* Now we know what sort of opcodes it is. Let's build the bytes. */#define INSERT(x,y) *x++ = y>>24; *x++ = y>> 16; *x++=y>>8; *x++ =y;static voidbuild_bytes (this_try, operand) opcode_entry_type *this_try; struct z8k_op *operand ATTRIBUTE_UNUSED;{ char *output_ptr = buffer; int c; int nib; int nibble; unsigned int *class_ptr; frag_wane (frag_now); frag_new (0); memset (buffer, 20, 0); class_ptr = this_try->byte_info; for (nibble = 0; (c = *class_ptr++); nibble++) { switch (c & CLASS_MASK) { default: abort (); case CLASS_ADDRESS: /* Direct address, we don't cope with the SS mode right now. */ if (segmented_mode) { /* da_operand->X_add_number |= 0x80000000; -- Now set at relocation time. */ output_ptr = apply_fix (output_ptr, R_IMM32, da_operand, 8); } else { output_ptr = apply_fix (output_ptr, R_IMM16, da_operand, 4); } da_operand = 0; break; case CLASS_DISP8: /* pc rel 8 bit */ output_ptr = apply_fix (output_ptr, R_JR, da_operand, 2); da_operand = 0; break; case CLASS_0DISP7: /* pc rel 7 bit */ *output_ptr = 0; output_ptr = apply_fix (output_ptr, R_DISP7, da_operand, 2); da_operand = 0; break; case CLASS_1DISP7: /* pc rel 7 bit */ *output_ptr = 0x80; output_ptr = apply_fix (output_ptr, R_DISP7, da_operand, 2); output_ptr[-2] = 0x8; da_operand = 0; break; case CLASS_BIT_1OR2: *output_ptr = c & 0xf; if (imm_operand) { if (imm_operand->X_add_number == 2) *output_ptr |= 2; else if (imm_operand->X_add_number != 1) as_bad (_("immediate must be 1 or 2")); } else as_bad (_("immediate 1 or 2 expected")); output_ptr++; break; case CLASS_CC: *output_ptr++ = the_cc; break; case CLASS_0CCC: *output_ptr++ = the_ctrl; break; case CLASS_1CCC: *output_ptr++ = the_ctrl | 0x8; break; case CLASS_00II: *output_ptr++ = (~the_interrupt & 0x3); break; case CLASS_01II: *output_ptr++ = (~the_interrupt & 0x3) | 0x4; break; case CLASS_FLAGS: *output_ptr++ = the_flags; break; case CLASS_BIT: *output_ptr++ = c & 0xf; break; case CLASS_REGN0: if (reg[c & 0xf] == 0) as_bad (_("can't use R0 here")); /* Fall through. */ case CLASS_REG: case CLASS_REG_BYTE: case CLASS_REG_WORD: case CLASS_REG_LONG: case CLASS_REG_QUAD: /* Insert bit mattern of right reg. */ *output_ptr++ = reg[c & 0xf]; break; case CLASS_DISP: switch (c & ARG_MASK) { case ARG_DISP12: output_ptr = apply_fix (output_ptr, R_CALLR, da_operand, 4); break; case ARG_DISP16: output_ptr = apply_fix (output_ptr, R_REL16, da_operand, 4); break; default: output_ptr = apply_fix (output_ptr, R_IMM16, da_operand, 4); } da_operand = 0; break; case CLASS_IMM: { nib = 0; switch (c & ARG_MASK) { case ARG_IMM4: output_ptr = apply_fix (output_ptr, R_IMM4L, imm_operand, 1); break; case ARG_IMM4M1: imm_operand->X_add_number--; output_ptr = apply_fix (output_ptr, R_IMM4L, imm_operand, 1); break; case ARG_IMMNMINUS1: imm_operand->X_add_number--; output_ptr = apply_fix (output_ptr, R_IMM4L, imm_operand, 1); break; case ARG_NIM8: imm_operand->X_add_number = -imm_operand->X_add_number; case ARG_IMM8: output_ptr = apply_fix (output_ptr, R_IMM8, imm_operand, 2); break; case ARG_IMM16: output_ptr = apply_fix (output_ptr, R_IMM16, imm_operand, 4); break; case ARG_IMM32: output_ptr = apply_fix (output_ptr, R_IMM32, imm_operand, 8); break; default: abort (); } } } } /* Copy from the nibble buffer into the frag. */ { int length = (output_ptr - buffer) / 2; char *src = buffer; char *fragp = frag_more (length); while (src < output_ptr) { *fragp = (src[0] << 4) | src[1]; src += 2; fragp++; } }}/* This is the guts of the machine-dependent assembler. STR points to a machine dependent instruction. This function is supposed to emit the frags/bytes it assembles to. */voidmd_assemble (str) char *str;{ char c; char *op_start; char *op_end; struct z8k_op operand[3]; opcode_entry_type *opcode; opcode_entry_type *prev_opcode; /* Drop leading whitespace. */ while (*str == ' ') str++; /* Find the op code end. */ for (op_start = op_end = str; *op_end != 0 && *op_end != ' '; op_end++) ; if (op_end == op_start) { as_bad (_("can't find opcode ")); } c = *op_end; *op_end = 0; opcode = (opcode_entry_type *) hash_find (opcode_hash_control, op_start); if (opcode == NULL) { as_bad (_("unknown opcode")); return; } if (opcode->opcode == 250) { /* Was really a pseudo op. */ pseudo_typeS *p; char oc; char *old = input_line_pointer; *op_end = c; input_line_pointer = op_end; oc = *old; *old = '\n'; while (*input_line_pointer == ' ') input_line_pointer++; p = (pseudo_typeS *) (opcode->func); (p->poc_handler) (p->poc_val); input_line_pointer = old; *old = oc; } else { input_line_pointer = get_operands (opcode, op_end, operand); prev_opcode = opcode; opcode = get_specific (opcode, operand); if (opcode == 0) { /* Couldn't find an opcode which matched the operands. */ char *where = frag_more (2); where[0] = 0x0; where[1] = 0x0; as_bad (_("Can't find opcode to match operands")); return; } build_bytes (opcode, operand); }}voidtc_crawl_symbol_chain (headers) object_headers *headers ATTRIBUTE_UNUSED;{ printf (_("call to tc_crawl_symbol_chain \n"));}symbolS *md_undefined_symbol (name) char *name ATTRIBUTE_UNUSED;{ return 0;}voidtc_headers_hook (headers) object_headers *headers ATTRIBUTE_UNUSED;{ printf (_("call to tc_headers_hook \n"));}/* Various routines to kill one day. *//* Equal to MAX_PRECISION in atof-ieee.c. */#define MAX_LITTLENUMS 6/* 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. An error message is returned, or NULL on OK. */char *md_atof (type, litP, sizeP) char type; char *litP; int *sizeP;{ int prec; LITTLENUM_TYPE words[MAX_LITTLENUMS]; LITTLENUM_TYPE *wordP; char *t; char *atof_ieee (); switch (type) { case 'f': case 'F': case 's': case 'S': prec = 2; break; case 'd': case 'D': case 'r': case 'R': prec = 4; break; case 'x': case 'X': prec = 6; break; case 'p': case 'P': prec = 6; break; default: *sizeP = 0; return _("Bad call to MD_ATOF()"); } t = atof_ieee (input_line_pointer, type, words); if (t) input_line_pointer = t; *sizeP = prec * sizeof (LITTLENUM_TYPE); for (wordP = words; prec--;) { md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE)); litP += sizeof (LITTLENUM_TYPE); } return 0;}CONST char *md_shortopts = "z:";struct option md_longopts[] = { {NULL, no_argument, NULL, 0}};size_t md_longopts_size = sizeof (md_longopts);intmd_parse_option (c, arg) int c; char *arg;{ switch (c) { case 'z': if (!strcmp (arg, "8001")) s_segm (); else if (!strcmp (arg, "8002")) s_unseg (); else { as_bad (_("invalid architecture -z%s"), arg); return 0; } break; default: return 0; } return 1;}voidmd_show_usage (stream) FILE *stream;{ fprintf (stream, _("\Z8K options:\n\-z8001 generate segmented code\n\-z8002 generate unsegmented code\n"));}voidtc_aout_fix_to_chars (){ printf (_("call to tc_aout_fix_to_chars \n")); abort ();}voidmd_convert_frag (headers, seg, fragP) object_headers *headers ATTRIBUTE_UNUSED; segT seg ATTRIBUTE_UNUSED; fragS *fragP ATTRIBUTE_UNUSED;{ printf (_("call to md_convert_frag \n")); abort ();}valueTmd_section_align (seg, size) segT seg; valueT size;{ return ((size + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg]));}voidmd_apply_fix (fixP, val) fixS *fixP; long val;{ char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; switch (fixP->fx_r_type) { case R_IMM4L: buf[0] = (buf[0] & 0xf0) | ((buf[0] + val) & 0xf); break; case R_JR: *buf++ = val;#if 0 if (val != 0) abort ();#endif break; case R_DISP7: *buf++ += val;#if 0 if (val != 0) abort ();#endif break; case R_IMM8: buf[0] += val; break; case R_IMM16: *buf++ = (val >> 8); *buf++ = val; break; case R_IMM32: *buf++ = (val >> 24); *buf++ = (val >> 16); *buf++ = (val >> 8); *buf++ = val; break;#if 0 case R_DA | R_SEG: *buf++ = (val >> 16); *buf++ = 0x00; *buf++ = (val >> 8); *buf++ = val; break;#endif case 0: md_number_to_chars (buf, val, fixP->fx_size); break; default: abort (); }}intmd_estimate_size_before_relax (fragP, segment_type) register fragS *fragP ATTRIBUTE_UNUSED; register segT segment_type ATTRIBUTE_UNUSED;{ printf (_("call tomd_estimate_size_before_relax \n")); abort ();}/* Put number into target byte order. */voidmd_number_to_chars (ptr, use, nbytes) char *ptr; valueT use; int nbytes;{ number_to_chars_bigendian (ptr, use, nbytes);}longmd_pcrel_from (fixP) fixS *fixP ATTRIBUTE_UNUSED;{ abort ();}voidtc_coff_symbol_emit_hook (s) symbolS *s ATTRIBUTE_UNUSED;{}voidtc_reloc_mangle (fix_ptr, intr, base) fixS *fix_ptr; struct internal_reloc *intr; bfd_vma base;{ symbolS *symbol_ptr; if (fix_ptr->fx_addsy && fix_ptr->fx_subsy) { symbolS *add = fix_ptr->fx_addsy; symbolS *sub = fix_ptr->fx_subsy; if (S_GET_SEGMENT (add) != S_GET_SEGMENT (sub)) as_bad (_("Can't subtract symbols in different sections %s %s"), S_GET_NAME (add), S_GET_NAME (sub)); else { int diff = S_GET_VALUE (add) - S_GET_VALUE (sub); fix_ptr->fx_addsy = 0; fix_ptr->fx_subsy = 0; fix_ptr->fx_offset += diff; } } symbol_ptr = fix_ptr->fx_addsy; /* If this relocation is attached to a symbol then it's ok to output it. */ if (fix_ptr->fx_r_type == 0) { /* cons likes to create reloc32's whatever the size of the reloc. */ switch (fix_ptr->fx_size) { case 2: intr->r_type = R_IMM16; break; case 1: intr->r_type = R_IMM8; break; case 4: intr->r_type = R_IMM32; break; default: abort (); } } else intr->r_type = fix_ptr->fx_r_type; intr->r_vaddr = fix_ptr->fx_frag->fr_address + fix_ptr->fx_where + base; intr->r_offset = fix_ptr->fx_offset; if (symbol_ptr) intr->r_symndx = symbol_ptr->sy_number; else intr->r_symndx = -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -