itbl-ops.c revision 60484
133965Sjdp/* itbl-ops.c
260484Sobrien   Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
333965Sjdp
433965Sjdp   This file is part of GAS, the GNU Assembler.
533965Sjdp
633965Sjdp   GAS is free software; you can redistribute it and/or modify
733965Sjdp   it under the terms of the GNU General Public License as published by
833965Sjdp   the Free Software Foundation; either version 2, or (at your option)
933965Sjdp   any later version.
1033965Sjdp
1133965Sjdp   GAS is distributed in the hope that it will be useful,
1233965Sjdp   but WITHOUT ANY WARRANTY; without even the implied warranty of
1333965Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1433965Sjdp   GNU General Public License for more details.
1533965Sjdp
1633965Sjdp   You should have received a copy of the GNU General Public License
1733965Sjdp   along with GAS; see the file COPYING.  If not, write to the Free
1833965Sjdp   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
1933965Sjdp   02111-1307, USA.  */
2033965Sjdp
2133965Sjdp/*======================================================================*/
2233965Sjdp/*
2333965Sjdp * Herein lies the support for dynamic specification of processor
2433965Sjdp * instructions and registers.  Mnemonics, values, and formats for each
2533965Sjdp * instruction and register are specified in an ascii file consisting of
2633965Sjdp * table entries.  The grammar for the table is defined in the document
2733965Sjdp * "Processor instruction table specification".
2833965Sjdp *
2933965Sjdp * Instructions use the gnu assembler syntax, with the addition of
3033965Sjdp * allowing mnemonics for register.
3133965Sjdp * Eg. "func $2,reg3,0x100,symbol ; comment"
3233965Sjdp * 	func - opcode name
3333965Sjdp * 	$n - register n
3433965Sjdp * 	reg3 - mnemonic for processor's register defined in table
3533965Sjdp * 	0xddd..d - immediate value
3633965Sjdp * 	symbol - address of label or external symbol
3733965Sjdp *
3833965Sjdp * First, itbl_parse reads in the table of register and instruction
3933965Sjdp * names and formats, and builds a list of entries for each
4033965Sjdp * processor/type combination.  lex and yacc are used to parse
4133965Sjdp * the entries in the table and call functions defined here to
4233965Sjdp * add each entry to our list.
4333965Sjdp *
4433965Sjdp * Then, when assembling or disassembling, these functions are called to
4533965Sjdp * 1) get information on a processor's registers and
4633965Sjdp * 2) assemble/disassemble an instruction.
4733965Sjdp * To assemble(disassemble) an instruction, the function
4833965Sjdp * itbl_assemble(itbl_disassemble) is called to search the list of
4933965Sjdp * instruction entries, and if a match is found, uses the format
5033965Sjdp * described in the instruction entry structure to complete the action.
5133965Sjdp *
5233965Sjdp * Eg. Suppose we have a Mips coprocessor "cop3" with data register "d2"
5333965Sjdp * and we want to define function "pig" which takes two operands.
5433965Sjdp *
5533965Sjdp * Given the table entries:
5633965Sjdp * 	"p3 insn pig 0x1:24-21 dreg:20-16 immed:15-0"
5733965Sjdp * 	"p3 dreg d2 0x2"
5833965Sjdp * and that the instruction encoding for coprocessor pz has encoding:
5933965Sjdp * 	#define MIPS_ENCODE_COP_NUM(z) ((0x21|(z<<1))<<25)
6033965Sjdp * 	#define ITBL_ENCODE_PNUM(pnum) MIPS_ENCODE_COP_NUM(pnum)
6133965Sjdp *
6233965Sjdp * a structure to describe the instruction might look something like:
6333965Sjdp *      struct itbl_entry = {
6433965Sjdp *      e_processor processor = e_p3
6533965Sjdp *      e_type type = e_insn
6633965Sjdp *      char *name = "pig"
6733965Sjdp *      uint value = 0x1
6833965Sjdp *      uint flags = 0
6933965Sjdp *      struct itbl_range range = 24-21
7033965Sjdp *      struct itbl_field *field = {
7133965Sjdp *              e_type type = e_dreg
7233965Sjdp *              struct itbl_range range = 20-16
7333965Sjdp *              struct itbl_field *next = {
7433965Sjdp *                      e_type type = e_immed
7533965Sjdp *                      struct itbl_range range = 15-0
7633965Sjdp *                      struct itbl_field *next = 0
7733965Sjdp *                      };
7833965Sjdp *              };
7933965Sjdp *      struct itbl_entry *next = 0
8033965Sjdp *      };
8133965Sjdp *
8233965Sjdp * And the assembler instructions:
8333965Sjdp * 	"pig d2,0x100"
8433965Sjdp * 	"pig $2,0x100"
8533965Sjdp *
8633965Sjdp * would both assemble to the hex value:
8733965Sjdp * 	"0x4e220100"
8833965Sjdp *
8933965Sjdp */
9033965Sjdp
9133965Sjdp#include <stdio.h>
9233965Sjdp#include <stdlib.h>
9333965Sjdp#include <string.h>
9433965Sjdp#include "itbl-ops.h"
9533965Sjdp#include "itbl-parse.h"
9633965Sjdp
9733965Sjdp/* #define DEBUG */
9833965Sjdp
9933965Sjdp#ifdef DEBUG
10033965Sjdp#include <assert.h>
10133965Sjdp#define ASSERT(x) assert(x)
10233965Sjdp#define DBG(x) printf x
10333965Sjdp#else
10433965Sjdp#define ASSERT(x)
10533965Sjdp#define DBG(x)
10633965Sjdp#endif
10733965Sjdp
10833965Sjdp#ifndef min
10933965Sjdp#define min(a,b) (a<b?a:b)
11033965Sjdp#endif
11133965Sjdp
11233965Sjdpint itbl_have_entries = 0;
11333965Sjdp
11433965Sjdp/*======================================================================*/
11533965Sjdp/* structures for keeping itbl format entries */
11633965Sjdp
11733965Sjdpstruct itbl_range
11833965Sjdp  {
11933965Sjdp    int sbit;			/* mask starting bit position */
12033965Sjdp    int ebit;			/* mask ending bit position */
12133965Sjdp  };
12233965Sjdp
12333965Sjdpstruct itbl_field
12433965Sjdp  {
12533965Sjdp    e_type type;		/* dreg/creg/greg/immed/symb */
12633965Sjdp    struct itbl_range range;	/* field's bitfield range within instruction */
12733965Sjdp    unsigned long flags;	/* field flags */
12833965Sjdp    struct itbl_field *next;	/* next field in list */
12933965Sjdp  };
13033965Sjdp
13133965Sjdp
13233965Sjdp/* These structures define the instructions and registers for a processor.
13333965Sjdp * If the type is an instruction, the structure defines the format of an
13433965Sjdp * instruction where the fields are the list of operands.
13533965Sjdp * The flags field below uses the same values as those defined in the
13633965Sjdp * gnu assembler and are machine specific. */
13733965Sjdpstruct itbl_entry
13833965Sjdp  {
13933965Sjdp    e_processor processor;	/* processor number */
14033965Sjdp    e_type type;		/* dreg/creg/greg/insn */
14133965Sjdp    char *name;			/* mnemionic name for insn/register */
14233965Sjdp    unsigned long value;	/* opcode/instruction mask/register number */
14333965Sjdp    unsigned long flags;	/* effects of the instruction */
14433965Sjdp    struct itbl_range range;	/* bit range within instruction for value */
14533965Sjdp    struct itbl_field *fields;	/* list of operand definitions (if any) */
14633965Sjdp    struct itbl_entry *next;	/* next entry */
14733965Sjdp  };
14833965Sjdp
14933965Sjdp
15033965Sjdp/* local data and structures */
15133965Sjdp
15233965Sjdpstatic int itbl_num_opcodes = 0;
15333965Sjdp/* Array of entries for each processor and entry type */
15433965Sjdpstatic struct itbl_entry *entries[e_nprocs][e_ntypes] =
15533965Sjdp{
15633965Sjdp  {0, 0, 0, 0, 0, 0},
15733965Sjdp  {0, 0, 0, 0, 0, 0},
15833965Sjdp  {0, 0, 0, 0, 0, 0},
15933965Sjdp  {0, 0, 0, 0, 0, 0}
16033965Sjdp};
16133965Sjdp
16233965Sjdp/* local prototypes */
16333965Sjdpstatic unsigned long build_opcode PARAMS ((struct itbl_entry *e));
16433965Sjdpstatic e_type get_type PARAMS ((int yytype));
16533965Sjdpstatic e_processor get_processor PARAMS ((int yyproc));
16633965Sjdpstatic struct itbl_entry **get_entries PARAMS ((e_processor processor,
16733965Sjdp						e_type type));
16833965Sjdpstatic struct itbl_entry *find_entry_byname PARAMS ((e_processor processor,
16933965Sjdp					e_type type, char *name));
17033965Sjdpstatic struct itbl_entry *find_entry_byval PARAMS ((e_processor processor,
17133965Sjdp			e_type type, unsigned long val, struct itbl_range *r));
17233965Sjdpstatic struct itbl_entry *alloc_entry PARAMS ((e_processor processor,
17333965Sjdp		e_type type, char *name, unsigned long value));
17433965Sjdpstatic unsigned long apply_range PARAMS ((unsigned long value,
17533965Sjdp						struct itbl_range r));
17633965Sjdpstatic unsigned long extract_range PARAMS ((unsigned long value,
17733965Sjdp						struct itbl_range r));
17833965Sjdpstatic struct itbl_field *alloc_field PARAMS ((e_type type, int sbit,
17933965Sjdp					int ebit, unsigned long flags));
18033965Sjdp
18133965Sjdp
18233965Sjdp/*======================================================================*/
18333965Sjdp/* Interfaces to the parser */
18433965Sjdp
18533965Sjdp
18633965Sjdp/* Open the table and use lex and yacc to parse the entries.
18733965Sjdp * Return 1 for failure; 0 for success.  */
18833965Sjdp
18933965Sjdpint
19033965Sjdpitbl_parse (char *insntbl)
19133965Sjdp{
19233965Sjdp  extern FILE *yyin;
19333965Sjdp  extern int yyparse (void);
19433965Sjdp  yyin = fopen (insntbl, "r");
19533965Sjdp  if (yyin == 0)
19633965Sjdp    {
19733965Sjdp      printf ("Can't open processor instruction specification file \"%s\"\n",
19833965Sjdp	      insntbl);
19933965Sjdp      return 1;
20033965Sjdp    }
20133965Sjdp  else
20233965Sjdp    {
20333965Sjdp      while (yyparse ());
20433965Sjdp    }
20533965Sjdp  fclose (yyin);
20633965Sjdp  itbl_have_entries = 1;
20733965Sjdp  return 0;
20833965Sjdp}
20933965Sjdp
21033965Sjdp/* Add a register entry */
21133965Sjdp
21233965Sjdpstruct itbl_entry *
21333965Sjdpitbl_add_reg (int yyprocessor, int yytype, char *regname,
21433965Sjdp	      int regnum)
21533965Sjdp{
21633965Sjdp#if 0
21733965Sjdp#include "as.h"
21833965Sjdp#include "symbols.h"
21933965Sjdp  /* Since register names don't have a prefix, we put them in the symbol table so
22033965Sjdp     they can't be used as symbols.  This also simplifies argument parsing as
22133965Sjdp     we can let gas parse registers for us.  The recorded register number is
22233965Sjdp     regnum.  */
22333965Sjdp  /* Use symbol_create here instead of symbol_new so we don't try to
22433965Sjdp     output registers into the object file's symbol table.  */
22533965Sjdp  symbol_table_insert (symbol_create (regname, reg_section,
22633965Sjdp				      regnum, &zero_address_frag));
22733965Sjdp#endif
22833965Sjdp  return alloc_entry (get_processor (yyprocessor), get_type (yytype), regname,
22933965Sjdp		      (unsigned long) regnum);
23033965Sjdp}
23133965Sjdp
23233965Sjdp/* Add an instruction entry */
23333965Sjdp
23433965Sjdpstruct itbl_entry *
23533965Sjdpitbl_add_insn (int yyprocessor, char *name, unsigned long value,
23633965Sjdp	       int sbit, int ebit, unsigned long flags)
23733965Sjdp{
23833965Sjdp  struct itbl_entry *e;
23933965Sjdp  e = alloc_entry (get_processor (yyprocessor), e_insn, name, value);
24033965Sjdp  if (e)
24133965Sjdp    {
24233965Sjdp      e->range.sbit = sbit;
24333965Sjdp      e->range.ebit = ebit;
24433965Sjdp      e->flags = flags;
24533965Sjdp      itbl_num_opcodes++;
24633965Sjdp    }
24733965Sjdp  return e;
24833965Sjdp}
24933965Sjdp
25033965Sjdp/* Add an operand to an instruction entry */
25133965Sjdp
25233965Sjdpstruct itbl_field *
25333965Sjdpitbl_add_operand (struct itbl_entry *e, int yytype, int sbit,
25433965Sjdp		  int ebit, unsigned long flags)
25533965Sjdp{
25633965Sjdp  struct itbl_field *f, **last_f;
25733965Sjdp  if (!e)
25833965Sjdp    return 0;
25933965Sjdp  /* Add to end of fields' list. */
26033965Sjdp  f = alloc_field (get_type (yytype), sbit, ebit, flags);
26133965Sjdp  if (f)
26233965Sjdp    {
26333965Sjdp      last_f = &e->fields;
26433965Sjdp      while (*last_f)
26533965Sjdp	last_f = &(*last_f)->next;
26633965Sjdp      *last_f = f;
26733965Sjdp      f->next = 0;
26833965Sjdp    }
26933965Sjdp  return f;
27033965Sjdp}
27133965Sjdp
27233965Sjdp
27333965Sjdp/*======================================================================*/
27433965Sjdp/* Interfaces for assembler and disassembler */
27533965Sjdp
27633965Sjdp#ifndef STAND_ALONE
27733965Sjdp#include "as.h"
27833965Sjdp#include "symbols.h"
27933965Sjdpstatic void append_insns_as_macros (void);
28033965Sjdp
28133965Sjdp/* initialize for gas */
28233965Sjdpvoid
28333965Sjdpitbl_init (void)
28433965Sjdp{
28533965Sjdp  struct itbl_entry *e, **es;
28633965Sjdp  e_processor procn;
28733965Sjdp  e_type type;
28833965Sjdp
28933965Sjdp  if (!itbl_have_entries)
29033965Sjdp	return;
29133965Sjdp
29233965Sjdp  /* Since register names don't have a prefix, put them in the symbol table so
29333965Sjdp     they can't be used as symbols.  This simplifies argument parsing as
29433965Sjdp     we can let gas parse registers for us. */
29533965Sjdp  /* Use symbol_create instead of symbol_new so we don't try to
29633965Sjdp     output registers into the object file's symbol table.  */
29733965Sjdp
29833965Sjdp  for (type = e_regtype0; type < e_nregtypes; type++)
29933965Sjdp    for (procn = e_p0; procn < e_nprocs; procn++)
30033965Sjdp      {
30133965Sjdp	es = get_entries (procn, type);
30233965Sjdp	for (e = *es; e; e = e->next)
30333965Sjdp	  {
30433965Sjdp	    symbol_table_insert (symbol_create (e->name, reg_section,
30533965Sjdp					     e->value, &zero_address_frag));
30633965Sjdp	  }
30733965Sjdp      }
30833965Sjdp  append_insns_as_macros ();
30933965Sjdp}
31033965Sjdp
31133965Sjdp
31233965Sjdp/* Append insns to opcodes table and increase number of opcodes
31333965Sjdp * Structure of opcodes table:
31433965Sjdp * struct itbl_opcode
31533965Sjdp * {
31633965Sjdp *   const char *name;
31733965Sjdp *   const char *args; 		- string describing the arguments.
31833965Sjdp *   unsigned long match; 	- opcode, or ISA level if pinfo=INSN_MACRO
31933965Sjdp *   unsigned long mask; 	- opcode mask, or macro id if pinfo=INSN_MACRO
32033965Sjdp *   unsigned long pinfo; 	- insn flags, or INSN_MACRO
32133965Sjdp * };
32233965Sjdp * examples:
32333965Sjdp *	{"li",      "t,i",  0x34000000, 0xffe00000, WR_t    },
32433965Sjdp *	{"li",      "t,I",  0,    (int) M_LI,   INSN_MACRO  },
32533965Sjdp */
32633965Sjdp
32733965Sjdpstatic char *form_args (struct itbl_entry *e);
32833965Sjdpstatic void
32933965Sjdpappend_insns_as_macros (void)
33033965Sjdp{
33133965Sjdp  struct ITBL_OPCODE_STRUCT *new_opcodes, *o;
33233965Sjdp  struct itbl_entry *e, **es;
33333965Sjdp  int n, id, size, new_size, new_num_opcodes;
33433965Sjdp
33533965Sjdp  if (!itbl_have_entries)
33633965Sjdp	return;
33733965Sjdp
33833965Sjdp  if (!itbl_num_opcodes)	/* no new instructions to add! */
33933965Sjdp    {
34033965Sjdp      return;
34133965Sjdp    }
34233965Sjdp  DBG (("previous num_opcodes=%d\n", ITBL_NUM_OPCODES));
34333965Sjdp
34433965Sjdp  new_num_opcodes = ITBL_NUM_OPCODES + itbl_num_opcodes;
34533965Sjdp  ASSERT (new_num_opcodes >= itbl_num_opcodes);
34633965Sjdp
34733965Sjdp  size = sizeof (struct ITBL_OPCODE_STRUCT) * ITBL_NUM_OPCODES;
34833965Sjdp  ASSERT (size >= 0);
34933965Sjdp  DBG (("I get=%d\n", size / sizeof (ITBL_OPCODES[0])));
35033965Sjdp
35133965Sjdp  new_size = sizeof (struct ITBL_OPCODE_STRUCT) * new_num_opcodes;
35233965Sjdp  ASSERT (new_size > size);
35333965Sjdp
35433965Sjdp  /* FIXME since ITBL_OPCODES culd be a static table,
35533965Sjdp		we can't realloc or delete the old memory. */
35633965Sjdp  new_opcodes = (struct ITBL_OPCODE_STRUCT *) malloc (new_size);
35733965Sjdp  if (!new_opcodes)
35833965Sjdp    {
35960484Sobrien      printf (_("Unable to allocate memory for new instructions\n"));
36033965Sjdp      return;
36133965Sjdp    }
36233965Sjdp  if (size)			/* copy prexisting opcodes table */
36333965Sjdp    memcpy (new_opcodes, ITBL_OPCODES, size);
36433965Sjdp
36533965Sjdp  /* FIXME! some NUMOPCODES are calculated expressions.
36633965Sjdp		These need to be changed before itbls can be supported. */
36733965Sjdp
36833965Sjdp  id = ITBL_NUM_MACROS;		/* begin the next macro id after the last */
36933965Sjdp  o = &new_opcodes[ITBL_NUM_OPCODES];	/* append macro to opcodes list */
37033965Sjdp  for (n = e_p0; n < e_nprocs; n++)
37133965Sjdp    {
37233965Sjdp      es = get_entries (n, e_insn);
37333965Sjdp      for (e = *es; e; e = e->next)
37433965Sjdp	{
37533965Sjdp	  /* name,    args,   mask,       match,  pinfo
37633965Sjdp		 * {"li",      "t,i",  0x34000000, 0xffe00000, WR_t    },
37733965Sjdp		 * {"li",      "t,I",  0,    (int) M_LI,   INSN_MACRO  },
37833965Sjdp		 * Construct args from itbl_fields.
37933965Sjdp		*/
38033965Sjdp	  o->name = e->name;
38133965Sjdp	  o->args = strdup (form_args (e));
38233965Sjdp	  o->mask = apply_range (e->value, e->range);
38333965Sjdp	  /* FIXME how to catch durring assembly? */
38433965Sjdp	  /* mask to identify this insn */
38533965Sjdp	  o->match = apply_range (e->value, e->range);
38633965Sjdp	  o->pinfo = 0;
38733965Sjdp
38833965Sjdp#ifdef USE_MACROS
38933965Sjdp	  o->mask = id++;	/* FIXME how to catch durring assembly? */
39033965Sjdp	  o->match = 0;		/* for macros, the insn_isa number */
39133965Sjdp	  o->pinfo = INSN_MACRO;
39233965Sjdp#endif
39333965Sjdp
39433965Sjdp	  /* Don't add instructions which caused an error */
39533965Sjdp	  if (o->args)
39633965Sjdp	    o++;
39733965Sjdp	  else
39833965Sjdp	    new_num_opcodes--;
39933965Sjdp	}
40033965Sjdp    }
40133965Sjdp  ITBL_OPCODES = new_opcodes;
40233965Sjdp  ITBL_NUM_OPCODES = new_num_opcodes;
40333965Sjdp
40433965Sjdp  /* FIXME
40533965Sjdp		At this point, we can free the entries, as they should have
40633965Sjdp		been added to the assembler's tables.
40733965Sjdp		Don't free name though, since name is being used by the new
40833965Sjdp		opcodes table.
40933965Sjdp
41033965Sjdp		Eventually, we should also free the new opcodes table itself
41133965Sjdp		on exit.
41233965Sjdp	*/
41333965Sjdp}
41433965Sjdp
41533965Sjdpstatic char *
41633965Sjdpform_args (struct itbl_entry *e)
41733965Sjdp{
41833965Sjdp  static char s[31];
41933965Sjdp  char c = 0, *p = s;
42033965Sjdp  struct itbl_field *f;
42133965Sjdp
42233965Sjdp  ASSERT (e);
42333965Sjdp  for (f = e->fields; f; f = f->next)
42433965Sjdp    {
42533965Sjdp      switch (f->type)
42633965Sjdp	{
42733965Sjdp	case e_dreg:
42833965Sjdp	  c = 'd';
42933965Sjdp	  break;
43033965Sjdp	case e_creg:
43133965Sjdp	  c = 't';
43233965Sjdp	  break;
43333965Sjdp	case e_greg:
43433965Sjdp	  c = 's';
43533965Sjdp	  break;
43633965Sjdp	case e_immed:
43733965Sjdp	  c = 'i';
43833965Sjdp	  break;
43933965Sjdp	case e_addr:
44033965Sjdp	  c = 'a';
44133965Sjdp	  break;
44233965Sjdp	default:
44333965Sjdp	  c = 0;		/* ignore; unknown field type */
44433965Sjdp	}
44533965Sjdp      if (c)
44633965Sjdp	{
44733965Sjdp	  if (p != s)
44833965Sjdp	    *p++ = ',';
44933965Sjdp	  *p++ = c;
45033965Sjdp	}
45133965Sjdp    }
45233965Sjdp  *p = 0;
45333965Sjdp  return s;
45433965Sjdp}
45533965Sjdp#endif /* !STAND_ALONE */
45633965Sjdp
45733965Sjdp
45833965Sjdp/* Get processor's register name from val */
45933965Sjdp
46060484Sobrienint
46160484Sobrienitbl_get_reg_val (char *name, unsigned long *pval)
46233965Sjdp{
46333965Sjdp  e_type t;
46433965Sjdp  e_processor p;
46560484Sobrien
46633965Sjdp  for (p = e_p0; p < e_nprocs; p++)
46760484Sobrien    {
46860484Sobrien      for (t = e_regtype0; t < e_nregtypes; t++)
46960484Sobrien	{
47060484Sobrien	  if (itbl_get_val (p, t, name, pval))
47160484Sobrien	    return 1;
47260484Sobrien	}
47360484Sobrien    }
47433965Sjdp  return 0;
47533965Sjdp}
47633965Sjdp
47733965Sjdpchar *
47833965Sjdpitbl_get_name (e_processor processor, e_type type, unsigned long val)
47933965Sjdp{
48033965Sjdp  struct itbl_entry *r;
48133965Sjdp  /* type depends on instruction passed */
48233965Sjdp  r = find_entry_byval (processor, type, val, 0);
48333965Sjdp  if (r)
48433965Sjdp    return r->name;
48533965Sjdp  else
48633965Sjdp    return 0;			/* error; invalid operand */
48733965Sjdp}
48833965Sjdp
48933965Sjdp/* Get processor's register value from name */
49033965Sjdp
49160484Sobrienint
49260484Sobrienitbl_get_val (e_processor processor, e_type type, char *name,
49360484Sobrien	      unsigned long *pval)
49433965Sjdp{
49533965Sjdp  struct itbl_entry *r;
49633965Sjdp  /* type depends on instruction passed */
49733965Sjdp  r = find_entry_byname (processor, type, name);
49860484Sobrien  if (r == NULL)
49960484Sobrien    return 0;
50060484Sobrien  *pval = r->value;
50160484Sobrien  return 1;
50233965Sjdp}
50333965Sjdp
50433965Sjdp
50533965Sjdp/* Assemble instruction "name" with operands "s".
50633965Sjdp * name - name of instruction
50733965Sjdp * s - operands
50833965Sjdp * returns - long word for assembled instruction */
50933965Sjdp
51033965Sjdpunsigned long
51133965Sjdpitbl_assemble (char *name, char *s)
51233965Sjdp{
51333965Sjdp  unsigned long opcode;
51433965Sjdp  struct itbl_entry *e;
51533965Sjdp  struct itbl_field *f;
51633965Sjdp  char *n;
51733965Sjdp  int processor;
51833965Sjdp
51933965Sjdp  if (!name || !*name)
52033965Sjdp    return 0;			/* error!  must have a opcode name/expr */
52133965Sjdp
52233965Sjdp  /* find entry in list of instructions for all processors */
52333965Sjdp  for (processor = 0; processor < e_nprocs; processor++)
52433965Sjdp    {
52533965Sjdp      e = find_entry_byname (processor, e_insn, name);
52633965Sjdp      if (e)
52733965Sjdp	break;
52833965Sjdp    }
52933965Sjdp  if (!e)
53033965Sjdp    return 0;			/* opcode not in table; invalid instrustion */
53133965Sjdp  opcode = build_opcode (e);
53233965Sjdp
53333965Sjdp  /* parse opcode's args (if any) */
53433965Sjdp  for (f = e->fields; f; f = f->next)	/* for each arg, ... */
53533965Sjdp    {
53633965Sjdp      struct itbl_entry *r;
53733965Sjdp      unsigned long value;
53833965Sjdp      if (!s || !*s)
53933965Sjdp	return 0;		/* error - not enough operands */
54033965Sjdp      n = itbl_get_field (&s);
54133965Sjdp      /* n should be in form $n or 0xhhh (are symbol names valid?? */
54233965Sjdp      switch (f->type)
54333965Sjdp	{
54433965Sjdp	case e_dreg:
54533965Sjdp	case e_creg:
54633965Sjdp	case e_greg:
54733965Sjdp	  /* Accept either a string name
54833965Sjdp			 * or '$' followed by the register number */
54933965Sjdp	  if (*n == '$')
55033965Sjdp	    {
55133965Sjdp	      n++;
55233965Sjdp	      value = strtol (n, 0, 10);
55333965Sjdp	      /* FIXME! could have "0l"... then what?? */
55433965Sjdp	      if (value == 0 && *n != '0')
55533965Sjdp		return 0;	/* error; invalid operand */
55633965Sjdp	    }
55733965Sjdp	  else
55833965Sjdp	    {
55933965Sjdp	      r = find_entry_byname (e->processor, f->type, n);
56033965Sjdp	      if (r)
56133965Sjdp		value = r->value;
56233965Sjdp	      else
56333965Sjdp		return 0;	/* error; invalid operand */
56433965Sjdp	    }
56533965Sjdp	  break;
56633965Sjdp	case e_addr:
56733965Sjdp	  /* use assembler's symbol table to find symbol */
56833965Sjdp	  /* FIXME!! Do we need this?
56933965Sjdp				if so, what about relocs??
57033965Sjdp				my_getExpression (&imm_expr, s);
57133965Sjdp				return 0;	/-* error; invalid operand *-/
57233965Sjdp				break;
57333965Sjdp			*/
57433965Sjdp	  /* If not a symbol, fall thru to IMMED */
57533965Sjdp	case e_immed:
57633965Sjdp	  if (*n == '0' && *(n + 1) == 'x')	/* hex begins 0x... */
57733965Sjdp	    {
57833965Sjdp	      n += 2;
57933965Sjdp	      value = strtol (n, 0, 16);
58033965Sjdp	      /* FIXME! could have "0xl"... then what?? */
58133965Sjdp	    }
58233965Sjdp	  else
58333965Sjdp	    {
58433965Sjdp	      value = strtol (n, 0, 10);
58533965Sjdp	      /* FIXME! could have "0l"... then what?? */
58633965Sjdp	      if (value == 0 && *n != '0')
58733965Sjdp		return 0;	/* error; invalid operand */
58833965Sjdp	    }
58933965Sjdp	  break;
59033965Sjdp	default:
59133965Sjdp	  return 0;		/* error; invalid field spec */
59233965Sjdp	}
59333965Sjdp      opcode |= apply_range (value, f->range);
59433965Sjdp    }
59533965Sjdp  if (s && *s)
59633965Sjdp    return 0;			/* error - too many operands */
59733965Sjdp  return opcode;		/* done! */
59833965Sjdp}
59933965Sjdp
60033965Sjdp/* Disassemble instruction "insn".
60133965Sjdp * insn - instruction
60233965Sjdp * s - buffer to hold disassembled instruction
60333965Sjdp * returns - 1 if succeeded; 0 if failed
60433965Sjdp */
60533965Sjdp
60633965Sjdpint
60733965Sjdpitbl_disassemble (char *s, unsigned long insn)
60833965Sjdp{
60933965Sjdp  e_processor processor;
61033965Sjdp  struct itbl_entry *e;
61133965Sjdp  struct itbl_field *f;
61233965Sjdp
61333965Sjdp  if (!ITBL_IS_INSN (insn))
61433965Sjdp    return 0;			/* error*/
61533965Sjdp  processor = get_processor (ITBL_DECODE_PNUM (insn));
61633965Sjdp
61733965Sjdp  /* find entry in list */
61833965Sjdp  e = find_entry_byval (processor, e_insn, insn, 0);
61933965Sjdp  if (!e)
62033965Sjdp    return 0;			/* opcode not in table; invalid instrustion */
62133965Sjdp  strcpy (s, e->name);
62233965Sjdp
62333965Sjdp  /* parse insn's args (if any) */
62433965Sjdp  for (f = e->fields; f; f = f->next)	/* for each arg, ... */
62533965Sjdp    {
62633965Sjdp      struct itbl_entry *r;
62733965Sjdp      unsigned long value;
62833965Sjdp
62933965Sjdp      if (f == e->fields)	/* first operand is preceeded by tab */
63033965Sjdp	strcat (s, "\t");
63133965Sjdp      else			/* ','s separate following operands */
63233965Sjdp	strcat (s, ",");
63333965Sjdp      value = extract_range (insn, f->range);
63433965Sjdp      /* n should be in form $n or 0xhhh (are symbol names valid?? */
63533965Sjdp      switch (f->type)
63633965Sjdp	{
63733965Sjdp	case e_dreg:
63833965Sjdp	case e_creg:
63933965Sjdp	case e_greg:
64033965Sjdp	  /* Accept either a string name
64133965Sjdp			 * or '$' followed by the register number */
64233965Sjdp	  r = find_entry_byval (e->processor, f->type, value, &f->range);
64333965Sjdp	  if (r)
64433965Sjdp	    strcat (s, r->name);
64533965Sjdp	  else
64660484Sobrien	    sprintf (s, "%s$%lu", s, value);
64733965Sjdp	  break;
64833965Sjdp	case e_addr:
64933965Sjdp	  /* use assembler's symbol table to find symbol */
65033965Sjdp	  /* FIXME!! Do we need this?
65133965Sjdp			 *   if so, what about relocs??
65233965Sjdp			*/
65333965Sjdp	  /* If not a symbol, fall thru to IMMED */
65433965Sjdp	case e_immed:
65560484Sobrien	  sprintf (s, "%s0x%lx", s, value);
65633965Sjdp	  break;
65733965Sjdp	default:
65833965Sjdp	  return 0;		/* error; invalid field spec */
65933965Sjdp	}
66033965Sjdp    }
66133965Sjdp  return 1;			/* done! */
66233965Sjdp}
66333965Sjdp
66433965Sjdp/*======================================================================*/
66533965Sjdp/*
66633965Sjdp * Local functions for manipulating private structures containing
66733965Sjdp * the names and format for the new instructions and registers
66833965Sjdp * for each processor.
66933965Sjdp */
67033965Sjdp
67133965Sjdp/* Calculate instruction's opcode and function values from entry */
67233965Sjdp
67333965Sjdpstatic unsigned long
67433965Sjdpbuild_opcode (struct itbl_entry *e)
67533965Sjdp{
67633965Sjdp  unsigned long opcode;
67733965Sjdp
67833965Sjdp  opcode = apply_range (e->value, e->range);
67933965Sjdp  opcode |= ITBL_ENCODE_PNUM (e->processor);
68033965Sjdp  return opcode;
68133965Sjdp}
68233965Sjdp
68333965Sjdp/* Calculate absolute value given the relative value and bit position range
68433965Sjdp * within the instruction.
68533965Sjdp * The range is inclusive where 0 is least significant bit.
68633965Sjdp * A range of { 24, 20 } will have a mask of
68733965Sjdp * bit   3           2            1
68833965Sjdp * pos: 1098 7654 3210 9876 5432 1098 7654 3210
68933965Sjdp * bin: 0000 0001 1111 0000 0000 0000 0000 0000
69033965Sjdp * hex:    0    1    f    0    0    0    0    0
69133965Sjdp * mask: 0x01f00000.
69233965Sjdp */
69333965Sjdp
69433965Sjdpstatic unsigned long
69533965Sjdpapply_range (unsigned long rval, struct itbl_range r)
69633965Sjdp{
69733965Sjdp  unsigned long mask;
69833965Sjdp  unsigned long aval;
69933965Sjdp  int len = MAX_BITPOS - r.sbit;
70033965Sjdp
70133965Sjdp  ASSERT (r.sbit >= r.ebit);
70233965Sjdp  ASSERT (MAX_BITPOS >= r.sbit);
70333965Sjdp  ASSERT (r.ebit >= 0);
70433965Sjdp
70533965Sjdp  /* create mask by truncating 1s by shifting */
70633965Sjdp  mask = 0xffffffff << len;
70733965Sjdp  mask = mask >> len;
70833965Sjdp  mask = mask >> r.ebit;
70933965Sjdp  mask = mask << r.ebit;
71033965Sjdp
71133965Sjdp  aval = (rval << r.ebit) & mask;
71233965Sjdp  return aval;
71333965Sjdp}
71433965Sjdp
71533965Sjdp/* Calculate relative value given the absolute value and bit position range
71633965Sjdp * within the instruction.  */
71733965Sjdp
71833965Sjdpstatic unsigned long
71933965Sjdpextract_range (unsigned long aval, struct itbl_range r)
72033965Sjdp{
72133965Sjdp  unsigned long mask;
72233965Sjdp  unsigned long rval;
72333965Sjdp  int len = MAX_BITPOS - r.sbit;
72433965Sjdp
72533965Sjdp  /* create mask by truncating 1s by shifting */
72633965Sjdp  mask = 0xffffffff << len;
72733965Sjdp  mask = mask >> len;
72833965Sjdp  mask = mask >> r.ebit;
72933965Sjdp  mask = mask << r.ebit;
73033965Sjdp
73133965Sjdp  rval = (aval & mask) >> r.ebit;
73233965Sjdp  return rval;
73333965Sjdp}
73433965Sjdp
73533965Sjdp/* Extract processor's assembly instruction field name from s;
73633965Sjdp * forms are "n args" "n,args" or "n" */
73733965Sjdp/* Return next argument from string pointer "s" and advance s.
73860484Sobrien * delimiters are " ,()" */
73933965Sjdp
74033965Sjdpchar *
74133965Sjdpitbl_get_field (char **S)
74233965Sjdp{
74333965Sjdp  static char n[128];
74460484Sobrien  char *s;
74533965Sjdp  int len;
74633965Sjdp
74733965Sjdp  s = *S;
74833965Sjdp  if (!s || !*s)
74933965Sjdp    return 0;
75060484Sobrien  /* FIXME: This is a weird set of delimiters.  */
75160484Sobrien  len = strcspn (s, " \t,()");
75233965Sjdp  ASSERT (128 > len + 1);
75333965Sjdp  strncpy (n, s, len);
75433965Sjdp  n[len] = 0;
75533965Sjdp  if (s[len] == '\0')
75633965Sjdp    s = 0;			/* no more args */
75733965Sjdp  else
75833965Sjdp    s += len + 1;		/* advance to next arg */
75933965Sjdp
76033965Sjdp  *S = s;
76133965Sjdp  return n;
76233965Sjdp}
76333965Sjdp
76433965Sjdp/* Search entries for a given processor and type
76533965Sjdp * to find one matching the name "n".
76633965Sjdp * Return a pointer to the entry */
76733965Sjdp
76833965Sjdpstatic struct itbl_entry *
76933965Sjdpfind_entry_byname (e_processor processor,
77033965Sjdp		   e_type type, char *n)
77133965Sjdp{
77233965Sjdp  struct itbl_entry *e, **es;
77333965Sjdp
77433965Sjdp  es = get_entries (processor, type);
77533965Sjdp  for (e = *es; e; e = e->next)	/* for each entry, ... */
77633965Sjdp    {
77733965Sjdp      if (!strcmp (e->name, n))
77833965Sjdp	return e;
77933965Sjdp    }
78033965Sjdp  return 0;
78133965Sjdp}
78233965Sjdp
78333965Sjdp/* Search entries for a given processor and type
78433965Sjdp * to find one matching the value "val" for the range "r".
78533965Sjdp * Return a pointer to the entry.
78633965Sjdp * This function is used for disassembling fields of an instruction.
78733965Sjdp */
78833965Sjdp
78933965Sjdpstatic struct itbl_entry *
79033965Sjdpfind_entry_byval (e_processor processor, e_type type,
79133965Sjdp		  unsigned long val, struct itbl_range *r)
79233965Sjdp{
79333965Sjdp  struct itbl_entry *e, **es;
79433965Sjdp  unsigned long eval;
79533965Sjdp
79633965Sjdp  es = get_entries (processor, type);
79733965Sjdp  for (e = *es; e; e = e->next)	/* for each entry, ... */
79833965Sjdp    {
79933965Sjdp      if (processor != e->processor)
80033965Sjdp	continue;
80133965Sjdp      /* For insns, we might not know the range of the opcode,
80233965Sjdp	 * so a range of 0 will allow this routine to match against
80333965Sjdp	 * the range of the entry to be compared with.
80433965Sjdp	 * This could cause ambiguities.
80533965Sjdp	 * For operands, we get an extracted value and a range.
80633965Sjdp	 */
80733965Sjdp      /* if range is 0, mask val against the range of the compared entry. */
80833965Sjdp      if (r == 0)		/* if no range passed, must be whole 32-bits
80933965Sjdp			 * so create 32-bit value from entry's range */
81033965Sjdp	{
81133965Sjdp	  eval = apply_range (e->value, e->range);
81233965Sjdp	  val &= apply_range (0xffffffff, e->range);
81333965Sjdp	}
81460484Sobrien      else if ((r->sbit == e->range.sbit && r->ebit == e->range.ebit)
81560484Sobrien	       || (e->range.sbit == 0 && e->range.ebit == 0))
81633965Sjdp	{
81733965Sjdp	  eval = apply_range (e->value, *r);
81833965Sjdp	  val = apply_range (val, *r);
81933965Sjdp	}
82033965Sjdp      else
82133965Sjdp	continue;
82233965Sjdp      if (val == eval)
82333965Sjdp	return e;
82433965Sjdp    }
82533965Sjdp  return 0;
82633965Sjdp}
82733965Sjdp
82833965Sjdp/* Return a pointer to the list of entries for a given processor and type. */
82933965Sjdp
83033965Sjdpstatic struct itbl_entry **
83133965Sjdpget_entries (e_processor processor, e_type type)
83233965Sjdp{
83333965Sjdp  return &entries[processor][type];
83433965Sjdp}
83533965Sjdp
83633965Sjdp/* Return an integral value for the processor passed from yyparse. */
83733965Sjdp
83833965Sjdpstatic e_processor
83933965Sjdpget_processor (int yyproc)
84033965Sjdp{
84133965Sjdp  /* translate from yacc's processor to enum */
84233965Sjdp  if (yyproc >= e_p0 && yyproc < e_nprocs)
84333965Sjdp    return (e_processor) yyproc;
84433965Sjdp  return e_invproc;		/* error; invalid processor */
84533965Sjdp}
84633965Sjdp
84733965Sjdp/* Return an integral value for the entry type passed from yyparse. */
84833965Sjdp
84933965Sjdpstatic e_type
85033965Sjdpget_type (int yytype)
85133965Sjdp{
85233965Sjdp  switch (yytype)
85333965Sjdp    {
85433965Sjdp      /* translate from yacc's type to enum */
85533965Sjdp    case INSN:
85633965Sjdp      return e_insn;
85733965Sjdp    case DREG:
85833965Sjdp      return e_dreg;
85933965Sjdp    case CREG:
86033965Sjdp      return e_creg;
86133965Sjdp    case GREG:
86233965Sjdp      return e_greg;
86333965Sjdp    case ADDR:
86433965Sjdp      return e_addr;
86533965Sjdp    case IMMED:
86633965Sjdp      return e_immed;
86733965Sjdp    default:
86833965Sjdp      return e_invtype;		/* error; invalid type */
86933965Sjdp    }
87033965Sjdp}
87133965Sjdp
87233965Sjdp
87333965Sjdp/* Allocate and initialize an entry */
87433965Sjdp
87533965Sjdpstatic struct itbl_entry *
87633965Sjdpalloc_entry (e_processor processor, e_type type,
87733965Sjdp	     char *name, unsigned long value)
87833965Sjdp{
87933965Sjdp  struct itbl_entry *e, **es;
88033965Sjdp  if (!name)
88133965Sjdp    return 0;
88233965Sjdp  e = (struct itbl_entry *) malloc (sizeof (struct itbl_entry));
88333965Sjdp  if (e)
88433965Sjdp    {
88533965Sjdp      memset (e, 0, sizeof (struct itbl_entry));
88633965Sjdp      e->name = (char *) malloc (sizeof (strlen (name)) + 1);
88733965Sjdp      if (e->name)
88833965Sjdp	strcpy (e->name, name);
88933965Sjdp      e->processor = processor;
89033965Sjdp      e->type = type;
89133965Sjdp      e->value = value;
89233965Sjdp      es = get_entries (e->processor, e->type);
89333965Sjdp      e->next = *es;
89433965Sjdp      *es = e;
89533965Sjdp    }
89633965Sjdp  return e;
89733965Sjdp}
89833965Sjdp
89933965Sjdp/* Allocate and initialize an entry's field */
90033965Sjdp
90133965Sjdpstatic struct itbl_field *
90233965Sjdpalloc_field (e_type type, int sbit, int ebit,
90333965Sjdp	     unsigned long flags)
90433965Sjdp{
90533965Sjdp  struct itbl_field *f;
90633965Sjdp  f = (struct itbl_field *) malloc (sizeof (struct itbl_field));
90733965Sjdp  if (f)
90833965Sjdp    {
90933965Sjdp      memset (f, 0, sizeof (struct itbl_field));
91033965Sjdp      f->type = type;
91133965Sjdp      f->range.sbit = sbit;
91233965Sjdp      f->range.ebit = ebit;
91333965Sjdp      f->flags = flags;
91433965Sjdp    }
91533965Sjdp  return f;
91633965Sjdp}
917