📄 tc-i960.c
字号:
parse_expr (arg[1], &e); switch (e.X_op) { default: /* We're dependent on one or more symbols -- use "lda" */ arg[0] = "lda"; break; case O_constant: /* Try the following mappings: * ldconst 0,<reg> ->mov 0,<reg> * ldconst 31,<reg> ->mov 31,<reg> * ldconst 32,<reg> ->addo 1,31,<reg> * ldconst 62,<reg> ->addo 31,31,<reg> * ldconst 64,<reg> ->shlo 8,3,<reg> * ldconst -1,<reg> ->subo 1,0,<reg> * ldconst -31,<reg>->subo 31,0,<reg> * * anthing else becomes: * lda xxx,<reg> */ n = offs (e); if ((0 <= n) && (n <= 31)) { arg[0] = "mov"; } else if ((-31 <= n) && (n <= -1)) { arg[0] = "subo"; arg[3] = arg[2]; sprintf (buf, "%d", -n); arg[1] = buf; arg[2] = "0"; } else if ((32 <= n) && (n <= 62)) { arg[0] = "addo"; arg[3] = arg[2]; arg[1] = "31"; sprintf (buf, "%d", n - 31); arg[2] = buf; } else if ((shift = shift_ok (n)) != 0) { arg[0] = "shlo"; arg[3] = arg[2]; sprintf (buf, "%d", shift); arg[1] = buf; sprintf (buf2, "%d", n >> shift); arg[2] = buf2; } else { arg[0] = "lda"; } break; case O_illegal: as_bad (_("invalid constant")); return -1; break; } return (arg[3] == 0) ? 2 : 3;}/***************************************************************************** parse_memop: parse a memory operand This routine is based on the observation that the 4 mode bits of the MEMB format, taken individually, have fairly consistent meaning: M3 (bit 13): 1 if displacement is present (D_BIT) M2 (bit 12): 1 for MEMB instructions (MEMB_BIT) M1 (bit 11): 1 if index is present (I_BIT) M0 (bit 10): 1 if abase is present (A_BIT) So we parse the memory operand and set bits in the mode as we find things. Then at the end, if we go to MEMB format, we need only set the MEMB bit (M2) and our mode is built for us. Unfortunately, I said "fairly consistent". The exceptions: DBIA 0100 Would seem illegal, but means "abase-only". 0101 Would seem to mean "abase-only" -- it means IP-relative. Must be converted to 0100. 0110 Would seem to mean "index-only", but is reserved. We turn on the D bit and provide a 0 displacement. The other thing to observe is that we parse from the right, peeling things * off as we go: first any index spec, then any abase, then the displacement. *************************************************************************** */staticvoidparse_memop (memP, argP, optype) memS *memP; /* Where to put the results */ char *argP; /* Text of the operand to be parsed */ int optype; /* MEM1, MEM2, MEM4, MEM8, MEM12, or MEM16 */{ char *indexP; /* Pointer to index specification with "[]" removed */ char *p; /* Temp char pointer */ char iprel_flag; /* True if this is an IP-relative operand */ int regnum; /* Register number */ /* Scale factor: 1,2,4,8, or 16. Later converted to internal format (0,1,2,3,4 respectively). */ int scale; int mode; /* MEMB mode bits */ int *intP; /* Pointer to register number */ /* The following table contains the default scale factors for each type of memory instruction. It is accessed using (optype-MEM1) as an index -- thus it assumes the 'optype' constants are assigned consecutive values, in the order they appear in this table. */ static const int def_scale[] = { 1, /* MEM1 */ 2, /* MEM2 */ 4, /* MEM4 */ 8, /* MEM8 */ -1, /* MEM12 -- no valid default */ 16 /* MEM16 */ }; iprel_flag = mode = 0; /* Any index present? */ indexP = get_ispec (argP); if (indexP) { p = strchr (indexP, '*'); if (p == NULL) { /* No explicit scale -- use default for this instruction type and assembler mode. */ if (flag_mri) scale = 1; else /* GNU960 compatibility */ scale = def_scale[optype - MEM1]; } else { *p++ = '\0'; /* Eliminate '*' */ /* Now indexP->a '\0'-terminated register name, * and p->a scale factor. */ if (!strcmp (p, "16")) { scale = 16; } else if (strchr ("1248", *p) && (p[1] == '\0')) { scale = *p - '0'; } else { scale = -1; } } regnum = get_regnum (indexP); /* Get index reg. # */ if (!IS_RG_REG (regnum)) { as_bad (_("invalid index register")); return; } /* Convert scale to its binary encoding */ switch (scale) { case 1: scale = 0 << 7; break; case 2: scale = 1 << 7; break; case 4: scale = 2 << 7; break; case 8: scale = 3 << 7; break; case 16: scale = 4 << 7; break; default: as_bad (_("invalid scale factor")); return; }; memP->opcode |= scale | regnum; /* Set index bits in opcode */ mode |= I_BIT; /* Found a valid index spec */ } /* Any abase (Register Indirect) specification present? */ if ((p = strrchr (argP, '(')) != NULL) { /* "(" is there -- does it start a legal abase spec? If not, it could be part of a displacement expression. */ intP = (int *) hash_find (areg_hash, p); if (intP != NULL) { /* Got an abase here */ regnum = *intP; *p = '\0'; /* discard register spec */ if (regnum == IPREL) { /* We have to specialcase ip-rel mode */ iprel_flag = 1; } else { memP->opcode |= regnum << 14; mode |= A_BIT; } } } /* Any expression present? */ memP->e = argP; if (*argP != '\0') { mode |= D_BIT; } /* Special-case ip-relative addressing */ if (iprel_flag) { if (mode & I_BIT) { syntax (); } else { memP->opcode |= 5 << 10; /* IP-relative mode */ memP->disp = 32; } return; } /* Handle all other modes */ switch (mode) { case D_BIT | A_BIT: /* Go with MEMA instruction format for now (grow to MEMB later if 12 bits is not enough for the displacement). MEMA format has a single mode bit: set it to indicate that abase is present. */ memP->opcode |= MEMA_ABASE; memP->disp = 12; break; case D_BIT: /* Go with MEMA instruction format for now (grow to MEMB later if 12 bits is not enough for the displacement). */ memP->disp = 12; break; case A_BIT: /* For some reason, the bit string for this mode is not consistent: it should be 0 (exclusive of the MEMB bit), so we set it "by hand" here. */ memP->opcode |= MEMB_BIT; break; case A_BIT | I_BIT: /* set MEMB bit in mode, and OR in mode bits */ memP->opcode |= mode | MEMB_BIT; break; case I_BIT: /* Treat missing displacement as displacement of 0. */ mode |= D_BIT; /* Fall into next case. */ case D_BIT | A_BIT | I_BIT: case D_BIT | I_BIT: /* set MEMB bit in mode, and OR in mode bits */ memP->opcode |= mode | MEMB_BIT; memP->disp = 32; break; default: syntax (); break; }}/***************************************************************************** parse_po: parse machine-dependent pseudo-op This is a top-level routine for machine-dependent pseudo-ops. It slurps up the rest of the input line, breaks out the individual arguments, and dispatches them to the correct handler. *************************************************************************** */staticvoidparse_po (po_num) int po_num; /* Pseudo-op number: currently S_LEAFPROC or S_SYSPROC */{ /* Pointers operands, with no embedded whitespace. arg[0] unused, arg[1-3]->operands */ char *args[4]; int n_ops; /* Number of operands */ char *p; /* Pointer to beginning of unparsed argument string */ char eol; /* Character that indicated end of line */ extern char is_end_of_line[]; /* Advance input pointer to end of line. */ p = input_line_pointer; while (!is_end_of_line[(unsigned char) *input_line_pointer]) { input_line_pointer++; } eol = *input_line_pointer; /* Save end-of-line char */ *input_line_pointer = '\0'; /* Terminate argument list */ /* Parse out operands */ n_ops = get_args (p, args); if (n_ops == -1) { return; } /* Dispatch to correct handler */ switch (po_num) { case S_SYSPROC: s_sysproc (n_ops, args); break; case S_LEAFPROC: s_leafproc (n_ops, args); break; default: BAD_CASE (po_num); break; } /* Restore eol, so line numbers get updated correctly. Base assembler assumes we leave input pointer pointing at char following the eol. */ *input_line_pointer++ = eol;}/***************************************************************************** parse_regop: parse a register operand. In case of illegal operand, issue a message and return some valid information so instruction processing can continue. *************************************************************************** */staticvoidparse_regop (regopP, optext, opdesc) struct regop *regopP; /* Where to put description of register operand */ char *optext; /* Text of operand */ char opdesc; /* Descriptor byte: what's legal for this operand */{ int n; /* Register number */ expressionS e; /* Parsed expression */ /* See if operand is a register */ n = get_regnum (optext); if (n >= 0) { if (IS_RG_REG (n)) { /* global or local register */ if (!REG_ALIGN (opdesc, n)) { as_bad (_("unaligned register")); } regopP->n = n; regopP->mode = 0; regopP->special = 0; return; } else if (IS_FP_REG (n) && FP_OK (opdesc)) { /* Floating point register, and it's allowed */ regopP->n = n - FP0; regopP->mode = 1; regopP->special = 0; return; } else if (IS_SF_REG (n) && SFR_OK (opdesc)) { /* Special-function register, and it's allowed */ regopP->n = n - SF0; regopP->mode = 0; regopP->special = 1; if (!targ_has_sfr (regopP->n)) { as_bad (_("no such sfr in this architecture")); } return; } } else if (LIT_OK (opdesc)) { /* How about a literal? */ regopP->mode = 1; regopP->special = 0; if (FP_OK (opdesc)) { /* floating point literal acceptable */ /* Skip over 0f, 0d, or 0e prefix */ if ((optext[0] == '0') && (optext[1] >= 'd') && (optext[1] <= 'f')) { optext += 2; } if (!strcmp (optext, "0.0") || !strcmp (optext, "0")) { regopP->n = 0x10; return; } if (!strcmp (optext, "1.0") || !strcmp (optext, "1")) { regopP->n = 0x16; return; } } else { /* fixed point literal acceptable */ parse_expr (optext, &e); if (e.X_op != O_constant || (offs (e) < 0) || (offs (e) > 31)) { as_bad (_("illegal literal")); offs (e) = 0; } regopP->n = offs (e); return; } } /* Nothing worked */ syntax (); regopP->mode = 0; /* Register r0 is always a good one */ regopP->n = 0; regopP->special = 0;} /* parse_regop() *//***************************************************************************** reg_fmt: generate a REG-format instruction ***************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -