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 + -
显示快捷键?