tc-ns32k.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,407 行 · 第 1/4 页
C
2,407 行
switch (str[strl - 2]) { case 'b': mode = 28; break; case 'w': mode = 29; break; case 'd': mode = 30; break; case 'q': mode = 31; break; default: as_warn (_("Invalid scaled-indexed mode, use (b,w,d,q)")); if (str[strl - 3] != ':' || str[strl - 6] != '[' || str[strl - 5] == 'r' || str[strl - 4] < '0' || str[strl - 4] > '7') as_warn (_("Syntax in scaled-indexed mode, use [Rn:m] where n=[0..7] m={b,w,d,q}")); } /* Scaled index. */ if (recursive_level > 0) { as_warn (_("Scaled-indexed addressing mode combined with scaled-index")); return 0; } addr_modeP->am_size += 1; /* scaled index byte */ j = str[strl - 4] - '0'; /* store temporary */ str[strl - 6] = '\000'; /* nullterminate for recursive call */ i = addr_mode (str, addr_modeP, 1); if (!i || addr_modeP->mode == 20) { as_warn (_("Invalid or illegal addressing mode combined with scaled-index")); return 0; } addr_modeP->scaled_mode = addr_modeP->mode; /* Store the inferior mode. */ addr_modeP->mode = mode; addr_modeP->scaled_reg = j + 1; return -1; } } addr_modeP->mode = DEFAULT; /* Default to whatever. */ addr_modeP->disp[0] = str; return -1;}/* ptr points at string addr_modeP points at struct with result This routine calls addr_mode to determine the general addr.mode of the operand. When this is ready it parses the displacements for size specifying suffixes and determines size of immediate mode via ns32k-opcode. Also builds index bytes if needed. */intget_addr_mode (ptr, addr_modeP) char *ptr; addr_modeS *addr_modeP;{ int tmp; addr_mode (ptr, addr_modeP, 0); if (addr_modeP->mode == DEFAULT || addr_modeP->scaled_mode == -1) { /* Resolve ambigious operands, this shouldn't be necessary if one uses standard NSC operand syntax. But the sequent compiler doesn't!!! This finds a proper addressinging mode if it is implicitly stated. See ns32k-opcode.h. */ (void) evaluate_expr (&exprP, ptr); /* This call takes time Sigh! */ if (addr_modeP->mode == DEFAULT) { if (exprP.X_add_symbol || exprP.X_op_symbol) addr_modeP->mode = desc->default_model; /* We have a label. */ else addr_modeP->mode = desc->default_modec; /* We have a constant. */ } else { if (exprP.X_add_symbol || exprP.X_op_symbol) addr_modeP->scaled_mode = desc->default_model; else addr_modeP->scaled_mode = desc->default_modec; } /* Must put this mess down in addr_mode to handle the scaled case better. */ } /* It appears as the sequent compiler wants an absolute when we have a label without @. Constants becomes immediates besides the addr case. Think it does so with local labels too, not optimum, pcrel is better. When I have time I will make gas check this and select pcrel when possible Actually that is trivial. */ if (tmp = addr_modeP->scaled_reg) { /* Build indexbyte. */ tmp--; /* Remember regnumber comes incremented for flagpurpose. */ tmp |= addr_modeP->scaled_mode << 3; addr_modeP->index_byte = (char) tmp; addr_modeP->am_size += 1; } if (disp_test[addr_modeP->mode]) { register char c; register char suffix; register char suffix_sub; register int i; register char *toP; register char *fromP; /* There was a displacement, probe for length specifying suffix. */ addr_modeP->pcrel = 0; if (disp_test[addr_modeP->mode]) { /* There is a displacement. */ if (addr_modeP->mode == 27 || addr_modeP->scaled_mode == 27) /* Do we have pcrel. mode. */ addr_modeP->pcrel = 1; addr_modeP->im_disp = 1; for (i = 0; i < 2; i++) { suffix_sub = suffix = 0; if (toP = addr_modeP->disp[i]) { /* Suffix of expression, the largest size rules. */ fromP = toP; while (c = *fromP++) { *toP++ = c; if (c == ':') { switch (*fromP) { case '\0': as_warn (_("Premature end of suffix -- Defaulting to d")); suffix = 4; continue; case 'b': suffix_sub = 1; break; case 'w': suffix_sub = 2; break; case 'd': suffix_sub = 4; break; default: as_warn (_("Bad suffix after ':' use {b|w|d} Defaulting to d")); suffix = 4; } fromP ++; toP --; /* So we write over the ':' */ if (suffix < suffix_sub) suffix = suffix_sub; } } *toP = '\0'; /* Terminate properly. */ addr_modeP->disp_suffix[i] = suffix; addr_modeP->am_size += suffix ? suffix : 4; } } } } else { if (addr_modeP->mode == 20) { /* Look in ns32k_opcode for size. */ addr_modeP->disp_suffix[0] = addr_modeP->am_size = desc->im_size; addr_modeP->im_disp = 0; } } return addr_modeP->mode;}/* Read an optionlist. */voidoptlist (str, optionP, default_map) char *str; /* The string to extract options from. */ struct ns32k_option *optionP; /* How to search the string. */ unsigned long *default_map; /* Default pattern and output. */{ register int i, j, k, strlen1, strlen2; register char *patternP, *strP; strlen1 = strlen (str); if (strlen1 < 1) as_fatal (_("Very short instr to option, ie you can't do it on a NULLstr")); for (i = 0; optionP[i].pattern != 0; i++) { strlen2 = strlen (optionP[i].pattern); for (j = 0; j < strlen1; j++) { patternP = optionP[i].pattern; strP = &str[j]; for (k = 0; k < strlen2; k++) { if (*(strP++) != *(patternP++)) break; } if (k == strlen2) { /* match */ *default_map |= optionP[i].or; *default_map &= optionP[i].and; } } }}/* Search struct for symbols. This function is used to get the short integer form of reg names in the instructions lmr, smr, lpr, spr return true if str is found in list. */intlist_search (str, optionP, default_map) char *str; /* The string to match. */ struct ns32k_option *optionP; /* List to search. */ unsigned long *default_map; /* Default pattern and output. */{ register int i; for (i = 0; optionP[i].pattern != 0; i++) { if (!strncmp (optionP[i].pattern, str, 20)) { /* Use strncmp to be safe. */ *default_map |= optionP[i].or; *default_map &= optionP[i].and; return -1; } } as_warn (_("No such entry in list. (cpu/mmu register)")); return 0;}static voidevaluate_expr (resultP, ptr) expressionS *resultP; char *ptr;{ register char *tmp_line; tmp_line = input_line_pointer; input_line_pointer = ptr; expression (&exprP); input_line_pointer = tmp_line;}/* Convert operands to iif-format and adds bitfields to the opcode. Operands are parsed in such an order that the opcode is updated from its most significant bit, that is when the operand need to alter the opcode. Be carefull not to put to objects in the same iif-slot. */voidencode_operand (argc, argv, operandsP, suffixP, im_size, opcode_bit_ptr) int argc; char **argv; char *operandsP; char *suffixP; char im_size; char opcode_bit_ptr;{ register int i, j; char d; int pcrel, tmp, b, loop, pcrel_adjust; for (loop = 0; loop < argc; loop++) { /* What operand are we supposed to work on. */ i = operandsP[loop << 1] - '1'; if (i > 3) as_fatal (_("Internal consistency error. check ns32k-opcode.h")); pcrel = 0; pcrel_adjust = 0; tmp = 0; switch ((d = operandsP[(loop << 1) + 1])) { case 'f': /* operand of sfsr turns out to be a nasty specialcase */ opcode_bit_ptr -= 5; case 'Z': /* float not immediate */ case 'F': /* 32 bit float general form */ case 'L': /* 64 bit float */ case 'I': /* integer not immediate */ case 'B': /* byte */ case 'W': /* word */ case 'D': /* double-word */ case 'A': /* double-word gen-address-form ie no regs allowed */ get_addr_mode (argv[i], &addr_modeP); if ((addr_modeP.mode == 20) && (d == 'I' || d == 'Z' || d == 'A')) as_fatal (d == 'A'? _("Address of immediate operand"): _("Invalid immediate write operand.")); if (opcode_bit_ptr == desc->opcode_size) b = 4; else b = 6; for (j = b; j < (b + 2); j++) { if (addr_modeP.disp[j - b]) { IIF (j, 2, addr_modeP.disp_suffix[j - b], (unsigned long) addr_modeP.disp[j - b], 0, addr_modeP.pcrel, iif.instr_size, addr_modeP.im_disp, IND (BRANCH, BYTE), NULL, (addr_modeP.scaled_reg ? addr_modeP.scaled_mode : addr_modeP.mode), 0); } } opcode_bit_ptr -= 5; iif.iifP[1].object |= ((long) addr_modeP.mode) << opcode_bit_ptr; if (addr_modeP.scaled_reg) { j = b / 2; IIF (j, 1, 1, (unsigned long) addr_modeP.index_byte, 0, 0, 0, 0, 0, NULL, -1, 0); } break; case 'b': /* multiple instruction disp */ freeptr++; /* OVE:this is an useful hack */ sprintf (freeptr, "((%s-1)*%d)\000", argv[i], desc->im_size); argv[i] = freeptr; pcrel -= 1; /* make pcrel 0 inspite of what case 'p': wants */ /* fall thru */ case 'p': /* displacement - pc relative addressing */ pcrel += 1; /* fall thru */ case 'd': /* displacement */ iif.instr_size += suffixP[i] ? suffixP[i] : 4; IIF (12, 2, suffixP[i], (unsigned long) argv[i], 0, pcrel, pcrel_adjust, 1, IND (BRANCH, BYTE), NULL, -1, 0); break; case 'H': /* sequent-hack: the linker wants a bit set when bsr */ pcrel = 1; iif.instr_size += suffixP[i] ? suffixP[i] : 4; IIF (12, 2, suffixP[i], (unsigned long) argv[i], 0, pcrel, pcrel_adjust, 1, IND (BRANCH, BYTE), NULL, -1, 1); break; case 'q': /* quick */ opcode_bit_ptr -= 4; IIF (11, 2, 42, (unsigned long) argv[i], 0, 0, 0, 0, 0, bit_fix_new (4, opcode_bit_ptr, -8, 7, 0, 1, 0), -1, 0); break; case 'r': /* register number (3 bits) */ list_search (argv[i], opt6, &tmp); opcode_bit_ptr -= 3; iif.iifP[1].object |= tmp << opcode_bit_ptr; break; case 'O': /* setcfg instruction optionslist */ optlist (argv[i], opt3, &tmp); opcode_bit_ptr -= 4; iif.iifP[1].object |= tmp << 15; break; case 'C': /* cinv instruction optionslist */ optlist (argv[i], opt4, &tmp); opcode_bit_ptr -= 4; iif.iifP[1].object |= tmp << 15; /* insert the regtype in opcode */ break; case 'S': /* stringinstruction optionslist */ optlist (argv[i], opt5, &tmp); opcode_bit_ptr -= 4; iif.iifP[1].object |= tmp << 15; break; case 'u': case 'U': /* registerlist */ IIF (10, 1, 1, 0, 0, 0, 0, 0, 0, NULL, -1, 0); switch (operandsP[(i << 1) + 1]) { case 'u': /* restore, exit */ optlist (argv[i], opt1, &iif.iifP[10].object); break; case 'U': /* save,enter */ optlist (argv[i], opt2, &iif.iifP[10].object); break; } iif.instr_size += 1; break; case 'M': /* mmu register */ list_search (argv[i], mmureg, &tmp); opcode_bit_ptr -= 4; iif.iifP[1].object |= tmp << opcode_bit_ptr; break; case 'P': /* cpu register */ list_search (argv[i], cpureg, &tmp); opcode_bit_ptr -= 4; iif.iifP[1].object |= tmp << opcode_bit_ptr; break; case 'g': /* inss exts */ iif.instr_size += 1; /* 1 byte is allocated after the opcode */ IIF (10, 2, 1, (unsigned long) argv[i], /* i always 2 here */ 0, 0, 0, 0, 0, bit_fix_new (3, 5, 0, 7, 0, 0, 0), /* a bit_fix is targeted to the byte */ -1, 0); break; case 'G': IIF (11, 2, 42, (unsigned long) argv[i], /* i always 3 here */ 0, 0, 0, 0, 0, bit_fix_new (5, 0, 1, 32, -1, 0, -1), -1, 0); break; case 'i': iif.instr_size += 1; b = 2 + i; /* put the extension byte after opcode */ IIF (b, 2, 1, 0, 0, 0, 0, 0, 0, 0, -1, 0); break; default: as_fatal (_("Bad opcode-table-option, check in file ns32k-opcode.h")); } }}/* in: instruction line out: internal structure of instruction that has been prepared for direct conversion to fragment(s) and fixes in a systematical fashion Return-value = recursive_level. *//* Build iif of one assembly text line. */intparse (line, recursive_level) char *line; int recursive_level;{ register char *lineptr, c, suffix_separator; register int i; int argc, arg_type; char sqr, sep; char suffix[MAX_ARGS], *argv[MAX_ARGS]; /* No more than 4 operands. */ if (recursive_level <= 0) { /* Called from md_assemble. */ for (lineptr = line; (*lineptr) != '\0' && (*lineptr) != ' '; lineptr++) continue; c = *lineptr; *lineptr = '\0'; if (!(desc = (struct ns32k_opcode *) hash_find (inst_hash_handle, line))) as_fatal (_("No such opcode")); *lineptr = c; } else { lineptr = line; } argc = 0; if (*desc->operands) { if (*lineptr++ != '\0') { sqr = '['; sep = ','; while (*lineptr != '\0') { if (desc->operands[argc << 1]) { suffix[argc] = 0; arg_type = desc->operands[(argc << 1) + 1]; switch (arg_type) { case 'd': case 'b': case 'p': case 'H': /* The operand is supposed to be a displacement. */ /* Hackwarning: do not forget to update the 4 cases above when editing ns32k-opcode.h. */ suffix_separator = ':'; break; default: /* If this char occurs we loose. */ suffix_separator = '\255'; break; } suffix[argc] = 0; /* 0 when no ':' is encountered */ argv[argc] = freeptr; *freeptr = '\0'; while ((c = *lineptr) != '\0' && c != sep) { if (c == sqr) { if (sqr == '[') { sqr = ']'; sep = '\0'; } else { sqr = '['; sep = ','; } } if (c == suffix_separator) { /* ':' - label/suffix separator. */ switch (lineptr[1]) { case 'b': suffix[argc] = 1; break; case 'w': suffix[argc] = 2; break; case 'd': suffix[argc] = 4; break; default: as_warn (_("Bad suffix, defaulting to d")); suffix[argc] = 4; if (lineptr[1] == '\0' || lineptr[1] == sep) { lineptr += 1; continue; } break; } lineptr += 2; continue; } *freeptr++ = c; lineptr++; } *freeptr++ = '\0'; argc += 1; if (*lineptr == '\0') continue; lineptr += 1; } else { as_fatal (_("Too many operands passed to instruction")); } } } } if (argc != strlen (desc->operands) / 2) { if (strlen (desc->default_args)) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?