itbl-ops.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 903 行 · 第 1/2 页
C
903 行
e_type t; e_processor p; for (p = e_p0; p < e_nprocs; p++) { for (t = e_regtype0; t < e_nregtypes; t++) { if (itbl_get_val (p, t, name, pval)) return 1; } } return 0;}char *itbl_get_name (e_processor processor, e_type type, unsigned long val){ struct itbl_entry *r; /* type depends on instruction passed */ r = find_entry_byval (processor, type, val, 0); if (r) return r->name; else return 0; /* error; invalid operand */}/* Get processor's register value from name */intitbl_get_val (e_processor processor, e_type type, char *name, unsigned long *pval){ struct itbl_entry *r; /* type depends on instruction passed */ r = find_entry_byname (processor, type, name); if (r == NULL) return 0; *pval = r->value; return 1;}/* Assemble instruction "name" with operands "s". * name - name of instruction * s - operands * returns - long word for assembled instruction */unsigned longitbl_assemble (char *name, char *s){ unsigned long opcode; struct itbl_entry *e = NULL; struct itbl_field *f; char *n; int processor; if (!name || !*name) return 0; /* error! must have a opcode name/expr */ /* find entry in list of instructions for all processors */ for (processor = 0; processor < e_nprocs; processor++) { e = find_entry_byname (processor, e_insn, name); if (e) break; } if (!e) return 0; /* opcode not in table; invalid instruction */ opcode = build_opcode (e); /* parse opcode's args (if any) */ for (f = e->fields; f; f = f->next) /* for each arg, ... */ { struct itbl_entry *r; unsigned long value; if (!s || !*s) return 0; /* error - not enough operands */ n = itbl_get_field (&s); /* n should be in form $n or 0xhhh (are symbol names valid?? */ switch (f->type) { case e_dreg: case e_creg: case e_greg: /* Accept either a string name * or '$' followed by the register number */ if (*n == '$') { n++; value = strtol (n, 0, 10); /* FIXME! could have "0l"... then what?? */ if (value == 0 && *n != '0') return 0; /* error; invalid operand */ } else { r = find_entry_byname (e->processor, f->type, n); if (r) value = r->value; else return 0; /* error; invalid operand */ } break; case e_addr: /* use assembler's symbol table to find symbol */ /* FIXME!! Do we need this? if so, what about relocs?? my_getExpression (&imm_expr, s); return 0; /-* error; invalid operand *-/ break; */ /* If not a symbol, fall thru to IMMED */ case e_immed: if (*n == '0' && *(n + 1) == 'x') /* hex begins 0x... */ { n += 2; value = strtol (n, 0, 16); /* FIXME! could have "0xl"... then what?? */ } else { value = strtol (n, 0, 10); /* FIXME! could have "0l"... then what?? */ if (value == 0 && *n != '0') return 0; /* error; invalid operand */ } break; default: return 0; /* error; invalid field spec */ } opcode |= apply_range (value, f->range); } if (s && *s) return 0; /* error - too many operands */ return opcode; /* done! */}/* Disassemble instruction "insn". * insn - instruction * s - buffer to hold disassembled instruction * returns - 1 if succeeded; 0 if failed */intitbl_disassemble (char *s, unsigned long insn){ e_processor processor; struct itbl_entry *e; struct itbl_field *f; if (!ITBL_IS_INSN (insn)) return 0; /* error */ processor = get_processor (ITBL_DECODE_PNUM (insn)); /* find entry in list */ e = find_entry_byval (processor, e_insn, insn, 0); if (!e) return 0; /* opcode not in table; invalid instruction */ strcpy (s, e->name); /* Parse insn's args (if any). */ for (f = e->fields; f; f = f->next) /* for each arg, ... */ { struct itbl_entry *r; unsigned long value; if (f == e->fields) /* First operand is preceeded by tab. */ strcat (s, "\t"); else /* ','s separate following operands. */ strcat (s, ","); value = extract_range (insn, f->range); /* n should be in form $n or 0xhhh (are symbol names valid?? */ switch (f->type) { case e_dreg: case e_creg: case e_greg: /* Accept either a string name or '$' followed by the register number. */ r = find_entry_byval (e->processor, f->type, value, &f->range); if (r) strcat (s, r->name); else sprintf (s, "%s$%lu", s, value); break; case e_addr: /* Use assembler's symbol table to find symbol. */ /* FIXME!! Do we need this? If so, what about relocs?? */ /* If not a symbol, fall through to IMMED. */ case e_immed: sprintf (s, "%s0x%lx", s, value); break; default: return 0; /* error; invalid field spec */ } } return 1; /* Done! */}/*======================================================================*//* * Local functions for manipulating private structures containing * the names and format for the new instructions and registers * for each processor. *//* Calculate instruction's opcode and function values from entry */static unsigned longbuild_opcode (struct itbl_entry *e){ unsigned long opcode; opcode = apply_range (e->value, e->range); opcode |= ITBL_ENCODE_PNUM (e->processor); return opcode;}/* Calculate absolute value given the relative value and bit position range * within the instruction. * The range is inclusive where 0 is least significant bit. * A range of { 24, 20 } will have a mask of * bit 3 2 1 * pos: 1098 7654 3210 9876 5432 1098 7654 3210 * bin: 0000 0001 1111 0000 0000 0000 0000 0000 * hex: 0 1 f 0 0 0 0 0 * mask: 0x01f00000. */static unsigned longapply_range (unsigned long rval, struct itbl_range r){ unsigned long mask; unsigned long aval; int len = MAX_BITPOS - r.sbit; ASSERT (r.sbit >= r.ebit); ASSERT (MAX_BITPOS >= r.sbit); ASSERT (r.ebit >= 0); /* create mask by truncating 1s by shifting */ mask = 0xffffffff << len; mask = mask >> len; mask = mask >> r.ebit; mask = mask << r.ebit; aval = (rval << r.ebit) & mask; return aval;}/* Calculate relative value given the absolute value and bit position range * within the instruction. */static unsigned longextract_range (unsigned long aval, struct itbl_range r){ unsigned long mask; unsigned long rval; int len = MAX_BITPOS - r.sbit; /* create mask by truncating 1s by shifting */ mask = 0xffffffff << len; mask = mask >> len; mask = mask >> r.ebit; mask = mask << r.ebit; rval = (aval & mask) >> r.ebit; return rval;}/* Extract processor's assembly instruction field name from s; * forms are "n args" "n,args" or "n" *//* Return next argument from string pointer "s" and advance s. * delimiters are " ,()" */char *itbl_get_field (char **S){ static char n[128]; char *s; int len; s = *S; if (!s || !*s) return 0; /* FIXME: This is a weird set of delimiters. */ len = strcspn (s, " \t,()"); ASSERT (128 > len + 1); strncpy (n, s, len); n[len] = 0; if (s[len] == '\0') s = 0; /* no more args */ else s += len + 1; /* advance to next arg */ *S = s; return n;}/* Search entries for a given processor and type * to find one matching the name "n". * Return a pointer to the entry */static struct itbl_entry *find_entry_byname (e_processor processor, e_type type, char *n){ struct itbl_entry *e, **es; es = get_entries (processor, type); for (e = *es; e; e = e->next) /* for each entry, ... */ { if (!strcmp (e->name, n)) return e; } return 0;}/* Search entries for a given processor and type * to find one matching the value "val" for the range "r". * Return a pointer to the entry. * This function is used for disassembling fields of an instruction. */static struct itbl_entry *find_entry_byval (e_processor processor, e_type type, unsigned long val, struct itbl_range *r){ struct itbl_entry *e, **es; unsigned long eval; es = get_entries (processor, type); for (e = *es; e; e = e->next) /* for each entry, ... */ { if (processor != e->processor) continue; /* For insns, we might not know the range of the opcode, * so a range of 0 will allow this routine to match against * the range of the entry to be compared with. * This could cause ambiguities. * For operands, we get an extracted value and a range. */ /* if range is 0, mask val against the range of the compared entry. */ if (r == 0) /* if no range passed, must be whole 32-bits * so create 32-bit value from entry's range */ { eval = apply_range (e->value, e->range); val &= apply_range (0xffffffff, e->range); } else if ((r->sbit == e->range.sbit && r->ebit == e->range.ebit) || (e->range.sbit == 0 && e->range.ebit == 0)) { eval = apply_range (e->value, *r); val = apply_range (val, *r); } else continue; if (val == eval) return e; } return 0;}/* Return a pointer to the list of entries for a given processor and type. */static struct itbl_entry **get_entries (e_processor processor, e_type type){ return &entries[processor][type];}/* Return an integral value for the processor passed from yyparse. */static e_processorget_processor (int yyproc){ /* translate from yacc's processor to enum */ if (yyproc >= e_p0 && yyproc < e_nprocs) return (e_processor) yyproc; return e_invproc; /* error; invalid processor */}/* Return an integral value for the entry type passed from yyparse. */static e_typeget_type (int yytype){ switch (yytype) { /* translate from yacc's type to enum */ case INSN: return e_insn; case DREG: return e_dreg; case CREG: return e_creg; case GREG: return e_greg; case ADDR: return e_addr; case IMMED: return e_immed; default: return e_invtype; /* error; invalid type */ }}/* Allocate and initialize an entry */static struct itbl_entry *alloc_entry (e_processor processor, e_type type, char *name, unsigned long value){ struct itbl_entry *e, **es; if (!name) return 0; e = (struct itbl_entry *) malloc (sizeof (struct itbl_entry)); if (e) { memset (e, 0, sizeof (struct itbl_entry)); e->name = (char *) malloc (sizeof (strlen (name)) + 1); if (e->name) strcpy (e->name, name); e->processor = processor; e->type = type; e->value = value; es = get_entries (e->processor, e->type); e->next = *es; *es = e; } return e;}/* Allocate and initialize an entry's field */static struct itbl_field *alloc_field (e_type type, int sbit, int ebit, unsigned long flags){ struct itbl_field *f; f = (struct itbl_field *) malloc (sizeof (struct itbl_field)); if (f) { memset (f, 0, sizeof (struct itbl_field)); f->type = type; f->range.sbit = sbit; f->range.ebit = ebit; f->flags = flags; } return f;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?