itbl-ops.c revision 130561
133965Sjdp/* itbl-ops.c
278828Sobrien   Copyright 1997, 1999, 2000, 2001 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"
95107492Sobrien#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
11777298Sobrienstruct itbl_range {
11877298Sobrien  int sbit;			/* mask starting bit position */
11977298Sobrien  int ebit;			/* mask ending bit position */
12077298Sobrien};
12133965Sjdp
12277298Sobrienstruct itbl_field {
12377298Sobrien  e_type type;			/* dreg/creg/greg/immed/symb */
12477298Sobrien  struct itbl_range range;	/* field's bitfield range within instruction */
12577298Sobrien  unsigned long flags;		/* field flags */
12677298Sobrien  struct itbl_field *next;	/* next field in list */
12777298Sobrien};
12833965Sjdp
12933965Sjdp/* These structures define the instructions and registers for a processor.
13033965Sjdp * If the type is an instruction, the structure defines the format of an
13133965Sjdp * instruction where the fields are the list of operands.
13233965Sjdp * The flags field below uses the same values as those defined in the
13377298Sobrien * gnu assembler and are machine specific.  */
13477298Sobrienstruct itbl_entry {
13577298Sobrien  e_processor processor;	/* processor number */
13677298Sobrien  e_type type;			/* dreg/creg/greg/insn */
13777298Sobrien  char *name;			/* mnemionic name for insn/register */
13877298Sobrien  unsigned long value;		/* opcode/instruction mask/register number */
13977298Sobrien  unsigned long flags;		/* effects of the instruction */
14077298Sobrien  struct itbl_range range;	/* bit range within instruction for value */
14177298Sobrien  struct itbl_field *fields;	/* list of operand definitions (if any) */
14277298Sobrien  struct itbl_entry *next;	/* next entry */
14377298Sobrien};
14433965Sjdp
14533965Sjdp/* local data and structures */
14633965Sjdp
14733965Sjdpstatic int itbl_num_opcodes = 0;
14833965Sjdp/* Array of entries for each processor and entry type */
14977298Sobrienstatic struct itbl_entry *entries[e_nprocs][e_ntypes] = {
15033965Sjdp  {0, 0, 0, 0, 0, 0},
15133965Sjdp  {0, 0, 0, 0, 0, 0},
15233965Sjdp  {0, 0, 0, 0, 0, 0},
15333965Sjdp  {0, 0, 0, 0, 0, 0}
15433965Sjdp};
15533965Sjdp
15633965Sjdp/* local prototypes */
157130561Sobrienstatic unsigned long build_opcode (struct itbl_entry *e);
158130561Sobrienstatic e_type get_type (int yytype);
159130561Sobrienstatic e_processor get_processor (int yyproc);
160130561Sobrienstatic struct itbl_entry **get_entries (e_processor processor,
161130561Sobrien					e_type type);
162130561Sobrienstatic struct itbl_entry *find_entry_byname (e_processor processor,
163130561Sobrien					e_type type, char *name);
164130561Sobrienstatic struct itbl_entry *find_entry_byval (e_processor processor,
165130561Sobrien			e_type type, unsigned long val, struct itbl_range *r);
166130561Sobrienstatic struct itbl_entry *alloc_entry (e_processor processor,
167130561Sobrien		e_type type, char *name, unsigned long value);
168130561Sobrienstatic unsigned long apply_range (unsigned long value, struct itbl_range r);
169130561Sobrienstatic unsigned long extract_range (unsigned long value, struct itbl_range r);
170130561Sobrienstatic struct itbl_field *alloc_field (e_type type, int sbit,
171130561Sobrien					int ebit, unsigned long flags);
17233965Sjdp
17333965Sjdp/*======================================================================*/
17433965Sjdp/* Interfaces to the parser */
17533965Sjdp
17633965Sjdp/* Open the table and use lex and yacc to parse the entries.
17733965Sjdp * Return 1 for failure; 0 for success.  */
17833965Sjdp
17977298Sobrienint
18033965Sjdpitbl_parse (char *insntbl)
18133965Sjdp{
18233965Sjdp  extern FILE *yyin;
18333965Sjdp  extern int yyparse (void);
18489857Sobrien
18589857Sobrien  yyin = fopen (insntbl, FOPEN_RT);
18633965Sjdp  if (yyin == 0)
18733965Sjdp    {
18833965Sjdp      printf ("Can't open processor instruction specification file \"%s\"\n",
18933965Sjdp	      insntbl);
19033965Sjdp      return 1;
19133965Sjdp    }
19289857Sobrien
19389857Sobrien  while (yyparse ())
19489857Sobrien    ;
19589857Sobrien
19633965Sjdp  fclose (yyin);
19733965Sjdp  itbl_have_entries = 1;
19833965Sjdp  return 0;
19933965Sjdp}
20033965Sjdp
20133965Sjdp/* Add a register entry */
20233965Sjdp
20333965Sjdpstruct itbl_entry *
20433965Sjdpitbl_add_reg (int yyprocessor, int yytype, char *regname,
20533965Sjdp	      int regnum)
20633965Sjdp{
20777298Sobrien#if 0
20833965Sjdp#include "as.h"
20933965Sjdp#include "symbols.h"
21033965Sjdp  /* Since register names don't have a prefix, we put them in the symbol table so
21133965Sjdp     they can't be used as symbols.  This also simplifies argument parsing as
21233965Sjdp     we can let gas parse registers for us.  The recorded register number is
21333965Sjdp     regnum.  */
21433965Sjdp  /* Use symbol_create here instead of symbol_new so we don't try to
21533965Sjdp     output registers into the object file's symbol table.  */
21633965Sjdp  symbol_table_insert (symbol_create (regname, reg_section,
21733965Sjdp				      regnum, &zero_address_frag));
21833965Sjdp#endif
21933965Sjdp  return alloc_entry (get_processor (yyprocessor), get_type (yytype), regname,
22033965Sjdp		      (unsigned long) regnum);
22133965Sjdp}
22233965Sjdp
22333965Sjdp/* Add an instruction entry */
22433965Sjdp
22533965Sjdpstruct itbl_entry *
22633965Sjdpitbl_add_insn (int yyprocessor, char *name, unsigned long value,
22733965Sjdp	       int sbit, int ebit, unsigned long flags)
22833965Sjdp{
22933965Sjdp  struct itbl_entry *e;
23033965Sjdp  e = alloc_entry (get_processor (yyprocessor), e_insn, name, value);
23133965Sjdp  if (e)
23233965Sjdp    {
23333965Sjdp      e->range.sbit = sbit;
23433965Sjdp      e->range.ebit = ebit;
23533965Sjdp      e->flags = flags;
23633965Sjdp      itbl_num_opcodes++;
23733965Sjdp    }
23833965Sjdp  return e;
23933965Sjdp}
24033965Sjdp
24133965Sjdp/* Add an operand to an instruction entry */
24233965Sjdp
24333965Sjdpstruct itbl_field *
24433965Sjdpitbl_add_operand (struct itbl_entry *e, int yytype, int sbit,
24533965Sjdp		  int ebit, unsigned long flags)
24633965Sjdp{
24733965Sjdp  struct itbl_field *f, **last_f;
24833965Sjdp  if (!e)
24933965Sjdp    return 0;
25077298Sobrien  /* Add to end of fields' list.  */
25133965Sjdp  f = alloc_field (get_type (yytype), sbit, ebit, flags);
25233965Sjdp  if (f)
25333965Sjdp    {
25433965Sjdp      last_f = &e->fields;
25533965Sjdp      while (*last_f)
25633965Sjdp	last_f = &(*last_f)->next;
25733965Sjdp      *last_f = f;
25833965Sjdp      f->next = 0;
25933965Sjdp    }
26033965Sjdp  return f;
26133965Sjdp}
26233965Sjdp
26333965Sjdp/*======================================================================*/
26433965Sjdp/* Interfaces for assembler and disassembler */
26533965Sjdp
26633965Sjdp#ifndef STAND_ALONE
26733965Sjdp#include "as.h"
26833965Sjdp#include "symbols.h"
26933965Sjdpstatic void append_insns_as_macros (void);
27033965Sjdp
27177298Sobrien/* Initialize for gas.  */
27277298Sobrien
27377298Sobrienvoid
27433965Sjdpitbl_init (void)
27533965Sjdp{
27633965Sjdp  struct itbl_entry *e, **es;
27733965Sjdp  e_processor procn;
27833965Sjdp  e_type type;
27933965Sjdp
28033965Sjdp  if (!itbl_have_entries)
28177298Sobrien    return;
28233965Sjdp
28333965Sjdp  /* Since register names don't have a prefix, put them in the symbol table so
28433965Sjdp     they can't be used as symbols.  This simplifies argument parsing as
28577298Sobrien     we can let gas parse registers for us.  */
28633965Sjdp  /* Use symbol_create instead of symbol_new so we don't try to
28733965Sjdp     output registers into the object file's symbol table.  */
28833965Sjdp
28933965Sjdp  for (type = e_regtype0; type < e_nregtypes; type++)
29033965Sjdp    for (procn = e_p0; procn < e_nprocs; procn++)
29133965Sjdp      {
29233965Sjdp	es = get_entries (procn, type);
29333965Sjdp	for (e = *es; e; e = e->next)
29433965Sjdp	  {
29533965Sjdp	    symbol_table_insert (symbol_create (e->name, reg_section,
29677298Sobrien						e->value, &zero_address_frag));
29733965Sjdp	  }
29833965Sjdp      }
29933965Sjdp  append_insns_as_macros ();
30033965Sjdp}
30133965Sjdp
30277298Sobrien/* Append insns to opcodes table and increase number of opcodes
30377298Sobrien * Structure of opcodes table:
30433965Sjdp * struct itbl_opcode
30533965Sjdp * {
30633965Sjdp *   const char *name;
30777298Sobrien *   const char *args; 		- string describing the arguments.
30877298Sobrien *   unsigned long match; 	- opcode, or ISA level if pinfo=INSN_MACRO
30977298Sobrien *   unsigned long mask; 	- opcode mask, or macro id if pinfo=INSN_MACRO
31077298Sobrien *   unsigned long pinfo; 	- insn flags, or INSN_MACRO
31133965Sjdp * };
31233965Sjdp * examples:
31333965Sjdp *	{"li",      "t,i",  0x34000000, 0xffe00000, WR_t    },
31433965Sjdp *	{"li",      "t,I",  0,    (int) M_LI,   INSN_MACRO  },
31533965Sjdp */
31633965Sjdp
31733965Sjdpstatic char *form_args (struct itbl_entry *e);
31877298Sobrienstatic void
31933965Sjdpappend_insns_as_macros (void)
32033965Sjdp{
32133965Sjdp  struct ITBL_OPCODE_STRUCT *new_opcodes, *o;
32233965Sjdp  struct itbl_entry *e, **es;
32333965Sjdp  int n, id, size, new_size, new_num_opcodes;
32433965Sjdp
32533965Sjdp  if (!itbl_have_entries)
32677298Sobrien    return;
32733965Sjdp
32833965Sjdp  if (!itbl_num_opcodes)	/* no new instructions to add! */
32933965Sjdp    {
33033965Sjdp      return;
33133965Sjdp    }
33233965Sjdp  DBG (("previous num_opcodes=%d\n", ITBL_NUM_OPCODES));
33333965Sjdp
33433965Sjdp  new_num_opcodes = ITBL_NUM_OPCODES + itbl_num_opcodes;
33533965Sjdp  ASSERT (new_num_opcodes >= itbl_num_opcodes);
33633965Sjdp
33733965Sjdp  size = sizeof (struct ITBL_OPCODE_STRUCT) * ITBL_NUM_OPCODES;
33833965Sjdp  ASSERT (size >= 0);
33933965Sjdp  DBG (("I get=%d\n", size / sizeof (ITBL_OPCODES[0])));
34033965Sjdp
34133965Sjdp  new_size = sizeof (struct ITBL_OPCODE_STRUCT) * new_num_opcodes;
34233965Sjdp  ASSERT (new_size > size);
34333965Sjdp
34433965Sjdp  /* FIXME since ITBL_OPCODES culd be a static table,
34577298Sobrien		we can't realloc or delete the old memory.  */
34633965Sjdp  new_opcodes = (struct ITBL_OPCODE_STRUCT *) malloc (new_size);
34733965Sjdp  if (!new_opcodes)
34833965Sjdp    {
34960484Sobrien      printf (_("Unable to allocate memory for new instructions\n"));
35033965Sjdp      return;
35133965Sjdp    }
352130561Sobrien  if (size)			/* copy preexisting opcodes table */
35333965Sjdp    memcpy (new_opcodes, ITBL_OPCODES, size);
35433965Sjdp
35533965Sjdp  /* FIXME! some NUMOPCODES are calculated expressions.
35677298Sobrien		These need to be changed before itbls can be supported.  */
35733965Sjdp
35833965Sjdp  id = ITBL_NUM_MACROS;		/* begin the next macro id after the last */
35933965Sjdp  o = &new_opcodes[ITBL_NUM_OPCODES];	/* append macro to opcodes list */
36033965Sjdp  for (n = e_p0; n < e_nprocs; n++)
36133965Sjdp    {
36233965Sjdp      es = get_entries (n, e_insn);
36333965Sjdp      for (e = *es; e; e = e->next)
36433965Sjdp	{
36533965Sjdp	  /* name,    args,   mask,       match,  pinfo
36633965Sjdp		 * {"li",      "t,i",  0x34000000, 0xffe00000, WR_t    },
36733965Sjdp		 * {"li",      "t,I",  0,    (int) M_LI,   INSN_MACRO  },
36833965Sjdp		 * Construct args from itbl_fields.
36933965Sjdp		*/
37033965Sjdp	  o->name = e->name;
37133965Sjdp	  o->args = strdup (form_args (e));
37233965Sjdp	  o->mask = apply_range (e->value, e->range);
373130561Sobrien	  /* FIXME how to catch during assembly? */
37433965Sjdp	  /* mask to identify this insn */
37533965Sjdp	  o->match = apply_range (e->value, e->range);
37633965Sjdp	  o->pinfo = 0;
37733965Sjdp
37833965Sjdp#ifdef USE_MACROS
379130561Sobrien	  o->mask = id++;	/* FIXME how to catch during assembly? */
38033965Sjdp	  o->match = 0;		/* for macros, the insn_isa number */
38133965Sjdp	  o->pinfo = INSN_MACRO;
38233965Sjdp#endif
38333965Sjdp
38433965Sjdp	  /* Don't add instructions which caused an error */
38533965Sjdp	  if (o->args)
38633965Sjdp	    o++;
38733965Sjdp	  else
38833965Sjdp	    new_num_opcodes--;
38933965Sjdp	}
39033965Sjdp    }
39133965Sjdp  ITBL_OPCODES = new_opcodes;
39233965Sjdp  ITBL_NUM_OPCODES = new_num_opcodes;
39333965Sjdp
39433965Sjdp  /* FIXME
39533965Sjdp		At this point, we can free the entries, as they should have
39633965Sjdp		been added to the assembler's tables.
39733965Sjdp		Don't free name though, since name is being used by the new
39833965Sjdp		opcodes table.
39933965Sjdp
40077298Sobrien		Eventually, we should also free the new opcodes table itself
40133965Sjdp		on exit.
40233965Sjdp	*/
40333965Sjdp}
40433965Sjdp
40533965Sjdpstatic char *
40633965Sjdpform_args (struct itbl_entry *e)
40733965Sjdp{
40833965Sjdp  static char s[31];
40933965Sjdp  char c = 0, *p = s;
41033965Sjdp  struct itbl_field *f;
41133965Sjdp
41233965Sjdp  ASSERT (e);
41333965Sjdp  for (f = e->fields; f; f = f->next)
41433965Sjdp    {
41533965Sjdp      switch (f->type)
41633965Sjdp	{
41733965Sjdp	case e_dreg:
41833965Sjdp	  c = 'd';
41933965Sjdp	  break;
42033965Sjdp	case e_creg:
42133965Sjdp	  c = 't';
42233965Sjdp	  break;
42333965Sjdp	case e_greg:
42433965Sjdp	  c = 's';
42533965Sjdp	  break;
42633965Sjdp	case e_immed:
42733965Sjdp	  c = 'i';
42833965Sjdp	  break;
42933965Sjdp	case e_addr:
43033965Sjdp	  c = 'a';
43133965Sjdp	  break;
43233965Sjdp	default:
43333965Sjdp	  c = 0;		/* ignore; unknown field type */
43433965Sjdp	}
43533965Sjdp      if (c)
43633965Sjdp	{
43733965Sjdp	  if (p != s)
43833965Sjdp	    *p++ = ',';
43933965Sjdp	  *p++ = c;
44033965Sjdp	}
44133965Sjdp    }
44233965Sjdp  *p = 0;
44333965Sjdp  return s;
44433965Sjdp}
44533965Sjdp#endif /* !STAND_ALONE */
44633965Sjdp
44733965Sjdp/* Get processor's register name from val */
44833965Sjdp
44960484Sobrienint
45060484Sobrienitbl_get_reg_val (char *name, unsigned long *pval)
45133965Sjdp{
45233965Sjdp  e_type t;
45333965Sjdp  e_processor p;
45460484Sobrien
45533965Sjdp  for (p = e_p0; p < e_nprocs; p++)
45660484Sobrien    {
45760484Sobrien      for (t = e_regtype0; t < e_nregtypes; t++)
45860484Sobrien	{
45960484Sobrien	  if (itbl_get_val (p, t, name, pval))
46060484Sobrien	    return 1;
46160484Sobrien	}
46260484Sobrien    }
46333965Sjdp  return 0;
46433965Sjdp}
46533965Sjdp
46633965Sjdpchar *
46733965Sjdpitbl_get_name (e_processor processor, e_type type, unsigned long val)
46833965Sjdp{
46933965Sjdp  struct itbl_entry *r;
47033965Sjdp  /* type depends on instruction passed */
47133965Sjdp  r = find_entry_byval (processor, type, val, 0);
47233965Sjdp  if (r)
47333965Sjdp    return r->name;
47433965Sjdp  else
47533965Sjdp    return 0;			/* error; invalid operand */
47633965Sjdp}
47733965Sjdp
47833965Sjdp/* Get processor's register value from name */
47933965Sjdp
48060484Sobrienint
48160484Sobrienitbl_get_val (e_processor processor, e_type type, char *name,
48260484Sobrien	      unsigned long *pval)
48333965Sjdp{
48433965Sjdp  struct itbl_entry *r;
48533965Sjdp  /* type depends on instruction passed */
48633965Sjdp  r = find_entry_byname (processor, type, name);
48760484Sobrien  if (r == NULL)
48860484Sobrien    return 0;
48960484Sobrien  *pval = r->value;
49060484Sobrien  return 1;
49133965Sjdp}
49233965Sjdp
49333965Sjdp/* Assemble instruction "name" with operands "s".
49433965Sjdp * name - name of instruction
49533965Sjdp * s - operands
49633965Sjdp * returns - long word for assembled instruction */
49733965Sjdp
49877298Sobrienunsigned long
49933965Sjdpitbl_assemble (char *name, char *s)
50033965Sjdp{
50133965Sjdp  unsigned long opcode;
50278828Sobrien  struct itbl_entry *e = NULL;
50333965Sjdp  struct itbl_field *f;
50433965Sjdp  char *n;
50533965Sjdp  int processor;
50633965Sjdp
50733965Sjdp  if (!name || !*name)
50889857Sobrien    return 0;			/* error!  must have an opcode name/expr */
50933965Sjdp
51033965Sjdp  /* find entry in list of instructions for all processors */
51133965Sjdp  for (processor = 0; processor < e_nprocs; processor++)
51233965Sjdp    {
51333965Sjdp      e = find_entry_byname (processor, e_insn, name);
51433965Sjdp      if (e)
51533965Sjdp	break;
51633965Sjdp    }
51733965Sjdp  if (!e)
51877298Sobrien    return 0;			/* opcode not in table; invalid instruction */
51933965Sjdp  opcode = build_opcode (e);
52033965Sjdp
52133965Sjdp  /* parse opcode's args (if any) */
52277298Sobrien  for (f = e->fields; f; f = f->next)	/* for each arg, ...  */
52333965Sjdp    {
52433965Sjdp      struct itbl_entry *r;
52533965Sjdp      unsigned long value;
52633965Sjdp      if (!s || !*s)
52733965Sjdp	return 0;		/* error - not enough operands */
52833965Sjdp      n = itbl_get_field (&s);
52933965Sjdp      /* n should be in form $n or 0xhhh (are symbol names valid?? */
53033965Sjdp      switch (f->type)
53133965Sjdp	{
53233965Sjdp	case e_dreg:
53333965Sjdp	case e_creg:
53433965Sjdp	case e_greg:
53533965Sjdp	  /* Accept either a string name
53633965Sjdp			 * or '$' followed by the register number */
53733965Sjdp	  if (*n == '$')
53833965Sjdp	    {
53933965Sjdp	      n++;
54033965Sjdp	      value = strtol (n, 0, 10);
54133965Sjdp	      /* FIXME! could have "0l"... then what?? */
54233965Sjdp	      if (value == 0 && *n != '0')
54333965Sjdp		return 0;	/* error; invalid operand */
54433965Sjdp	    }
54533965Sjdp	  else
54633965Sjdp	    {
54733965Sjdp	      r = find_entry_byname (e->processor, f->type, n);
54833965Sjdp	      if (r)
54933965Sjdp		value = r->value;
55033965Sjdp	      else
55133965Sjdp		return 0;	/* error; invalid operand */
55233965Sjdp	    }
55333965Sjdp	  break;
55433965Sjdp	case e_addr:
55533965Sjdp	  /* use assembler's symbol table to find symbol */
55633965Sjdp	  /* FIXME!! Do we need this?
55733965Sjdp				if so, what about relocs??
55833965Sjdp				my_getExpression (&imm_expr, s);
55933965Sjdp				return 0;	/-* error; invalid operand *-/
56033965Sjdp				break;
56133965Sjdp			*/
56233965Sjdp	  /* If not a symbol, fall thru to IMMED */
56333965Sjdp	case e_immed:
56477298Sobrien	  if (*n == '0' && *(n + 1) == 'x')	/* hex begins 0x...  */
56533965Sjdp	    {
56633965Sjdp	      n += 2;
56733965Sjdp	      value = strtol (n, 0, 16);
56833965Sjdp	      /* FIXME! could have "0xl"... then what?? */
56933965Sjdp	    }
57033965Sjdp	  else
57133965Sjdp	    {
57233965Sjdp	      value = strtol (n, 0, 10);
57333965Sjdp	      /* FIXME! could have "0l"... then what?? */
57433965Sjdp	      if (value == 0 && *n != '0')
57533965Sjdp		return 0;	/* error; invalid operand */
57633965Sjdp	    }
57733965Sjdp	  break;
57833965Sjdp	default:
57933965Sjdp	  return 0;		/* error; invalid field spec */
58033965Sjdp	}
58133965Sjdp      opcode |= apply_range (value, f->range);
58233965Sjdp    }
58333965Sjdp  if (s && *s)
58433965Sjdp    return 0;			/* error - too many operands */
58533965Sjdp  return opcode;		/* done! */
58633965Sjdp}
58733965Sjdp
58833965Sjdp/* Disassemble instruction "insn".
58933965Sjdp * insn - instruction
59033965Sjdp * s - buffer to hold disassembled instruction
59133965Sjdp * returns - 1 if succeeded; 0 if failed
59233965Sjdp */
59333965Sjdp
59477298Sobrienint
59533965Sjdpitbl_disassemble (char *s, unsigned long insn)
59633965Sjdp{
59733965Sjdp  e_processor processor;
59833965Sjdp  struct itbl_entry *e;
59933965Sjdp  struct itbl_field *f;
60033965Sjdp
60133965Sjdp  if (!ITBL_IS_INSN (insn))
60277298Sobrien    return 0;			/* error */
60333965Sjdp  processor = get_processor (ITBL_DECODE_PNUM (insn));
60433965Sjdp
60533965Sjdp  /* find entry in list */
60633965Sjdp  e = find_entry_byval (processor, e_insn, insn, 0);
60733965Sjdp  if (!e)
60877298Sobrien    return 0;			/* opcode not in table; invalid instruction */
60933965Sjdp  strcpy (s, e->name);
61033965Sjdp
61177298Sobrien  /* Parse insn's args (if any).  */
61277298Sobrien  for (f = e->fields; f; f = f->next)	/* for each arg, ...  */
61333965Sjdp    {
61433965Sjdp      struct itbl_entry *r;
61533965Sjdp      unsigned long value;
61633965Sjdp
617130561Sobrien      if (f == e->fields)	/* First operand is preceded by tab.  */
61833965Sjdp	strcat (s, "\t");
61977298Sobrien      else			/* ','s separate following operands.  */
62033965Sjdp	strcat (s, ",");
62133965Sjdp      value = extract_range (insn, f->range);
62233965Sjdp      /* n should be in form $n or 0xhhh (are symbol names valid?? */
62333965Sjdp      switch (f->type)
62433965Sjdp	{
62533965Sjdp	case e_dreg:
62633965Sjdp	case e_creg:
62733965Sjdp	case e_greg:
62833965Sjdp	  /* Accept either a string name
62977298Sobrien	     or '$' followed by the register number.  */
63033965Sjdp	  r = find_entry_byval (e->processor, f->type, value, &f->range);
63133965Sjdp	  if (r)
63233965Sjdp	    strcat (s, r->name);
63333965Sjdp	  else
63460484Sobrien	    sprintf (s, "%s$%lu", s, value);
63533965Sjdp	  break;
63633965Sjdp	case e_addr:
63777298Sobrien	  /* Use assembler's symbol table to find symbol.  */
63877298Sobrien	  /* FIXME!! Do we need this?  If so, what about relocs??  */
63977298Sobrien	  /* If not a symbol, fall through to IMMED.  */
64033965Sjdp	case e_immed:
64160484Sobrien	  sprintf (s, "%s0x%lx", s, value);
64233965Sjdp	  break;
64333965Sjdp	default:
64433965Sjdp	  return 0;		/* error; invalid field spec */
64533965Sjdp	}
64633965Sjdp    }
64777298Sobrien  return 1;			/* Done!  */
64833965Sjdp}
64933965Sjdp
65033965Sjdp/*======================================================================*/
65133965Sjdp/*
65233965Sjdp * Local functions for manipulating private structures containing
65333965Sjdp * the names and format for the new instructions and registers
65433965Sjdp * for each processor.
65533965Sjdp */
65633965Sjdp
65733965Sjdp/* Calculate instruction's opcode and function values from entry */
65833965Sjdp
65977298Sobrienstatic unsigned long
66033965Sjdpbuild_opcode (struct itbl_entry *e)
66133965Sjdp{
66233965Sjdp  unsigned long opcode;
66333965Sjdp
66433965Sjdp  opcode = apply_range (e->value, e->range);
66533965Sjdp  opcode |= ITBL_ENCODE_PNUM (e->processor);
66633965Sjdp  return opcode;
66733965Sjdp}
66833965Sjdp
66933965Sjdp/* Calculate absolute value given the relative value and bit position range
67033965Sjdp * within the instruction.
67133965Sjdp * The range is inclusive where 0 is least significant bit.
67233965Sjdp * A range of { 24, 20 } will have a mask of
67333965Sjdp * bit   3           2            1
67433965Sjdp * pos: 1098 7654 3210 9876 5432 1098 7654 3210
67533965Sjdp * bin: 0000 0001 1111 0000 0000 0000 0000 0000
67633965Sjdp * hex:    0    1    f    0    0    0    0    0
67733965Sjdp * mask: 0x01f00000.
67833965Sjdp */
67933965Sjdp
68077298Sobrienstatic unsigned long
68133965Sjdpapply_range (unsigned long rval, struct itbl_range r)
68233965Sjdp{
68333965Sjdp  unsigned long mask;
68433965Sjdp  unsigned long aval;
68533965Sjdp  int len = MAX_BITPOS - r.sbit;
68633965Sjdp
68733965Sjdp  ASSERT (r.sbit >= r.ebit);
68833965Sjdp  ASSERT (MAX_BITPOS >= r.sbit);
68933965Sjdp  ASSERT (r.ebit >= 0);
69033965Sjdp
69133965Sjdp  /* create mask by truncating 1s by shifting */
69233965Sjdp  mask = 0xffffffff << len;
69333965Sjdp  mask = mask >> len;
69433965Sjdp  mask = mask >> r.ebit;
69533965Sjdp  mask = mask << r.ebit;
69633965Sjdp
69733965Sjdp  aval = (rval << r.ebit) & mask;
69833965Sjdp  return aval;
69933965Sjdp}
70033965Sjdp
70133965Sjdp/* Calculate relative value given the absolute value and bit position range
70233965Sjdp * within the instruction.  */
70333965Sjdp
70477298Sobrienstatic unsigned long
70533965Sjdpextract_range (unsigned long aval, struct itbl_range r)
70633965Sjdp{
70733965Sjdp  unsigned long mask;
70833965Sjdp  unsigned long rval;
70933965Sjdp  int len = MAX_BITPOS - r.sbit;
71033965Sjdp
71133965Sjdp  /* create mask by truncating 1s by shifting */
71233965Sjdp  mask = 0xffffffff << len;
71333965Sjdp  mask = mask >> len;
71433965Sjdp  mask = mask >> r.ebit;
71533965Sjdp  mask = mask << r.ebit;
71633965Sjdp
71733965Sjdp  rval = (aval & mask) >> r.ebit;
71833965Sjdp  return rval;
71933965Sjdp}
72033965Sjdp
72133965Sjdp/* Extract processor's assembly instruction field name from s;
72233965Sjdp * forms are "n args" "n,args" or "n" */
72333965Sjdp/* Return next argument from string pointer "s" and advance s.
72460484Sobrien * delimiters are " ,()" */
72533965Sjdp
72633965Sjdpchar *
72733965Sjdpitbl_get_field (char **S)
72833965Sjdp{
72933965Sjdp  static char n[128];
73060484Sobrien  char *s;
73133965Sjdp  int len;
73233965Sjdp
73333965Sjdp  s = *S;
73433965Sjdp  if (!s || !*s)
73533965Sjdp    return 0;
73660484Sobrien  /* FIXME: This is a weird set of delimiters.  */
73760484Sobrien  len = strcspn (s, " \t,()");
73833965Sjdp  ASSERT (128 > len + 1);
73933965Sjdp  strncpy (n, s, len);
74033965Sjdp  n[len] = 0;
74133965Sjdp  if (s[len] == '\0')
74233965Sjdp    s = 0;			/* no more args */
74333965Sjdp  else
74433965Sjdp    s += len + 1;		/* advance to next arg */
74533965Sjdp
74633965Sjdp  *S = s;
74733965Sjdp  return n;
74833965Sjdp}
74933965Sjdp
75033965Sjdp/* Search entries for a given processor and type
75133965Sjdp * to find one matching the name "n".
75233965Sjdp * Return a pointer to the entry */
75333965Sjdp
75433965Sjdpstatic struct itbl_entry *
75533965Sjdpfind_entry_byname (e_processor processor,
75633965Sjdp		   e_type type, char *n)
75733965Sjdp{
75833965Sjdp  struct itbl_entry *e, **es;
75933965Sjdp
76033965Sjdp  es = get_entries (processor, type);
76177298Sobrien  for (e = *es; e; e = e->next)	/* for each entry, ...  */
76233965Sjdp    {
76333965Sjdp      if (!strcmp (e->name, n))
76433965Sjdp	return e;
76533965Sjdp    }
76633965Sjdp  return 0;
76733965Sjdp}
76833965Sjdp
76933965Sjdp/* Search entries for a given processor and type
77033965Sjdp * to find one matching the value "val" for the range "r".
77133965Sjdp * Return a pointer to the entry.
77233965Sjdp * This function is used for disassembling fields of an instruction.
77333965Sjdp */
77433965Sjdp
77533965Sjdpstatic struct itbl_entry *
77633965Sjdpfind_entry_byval (e_processor processor, e_type type,
77733965Sjdp		  unsigned long val, struct itbl_range *r)
77833965Sjdp{
77933965Sjdp  struct itbl_entry *e, **es;
78033965Sjdp  unsigned long eval;
78133965Sjdp
78233965Sjdp  es = get_entries (processor, type);
78377298Sobrien  for (e = *es; e; e = e->next)	/* for each entry, ...  */
78433965Sjdp    {
78533965Sjdp      if (processor != e->processor)
78633965Sjdp	continue;
78733965Sjdp      /* For insns, we might not know the range of the opcode,
78833965Sjdp	 * so a range of 0 will allow this routine to match against
78933965Sjdp	 * the range of the entry to be compared with.
79033965Sjdp	 * This could cause ambiguities.
79133965Sjdp	 * For operands, we get an extracted value and a range.
79233965Sjdp	 */
79377298Sobrien      /* if range is 0, mask val against the range of the compared entry.  */
79433965Sjdp      if (r == 0)		/* if no range passed, must be whole 32-bits
79533965Sjdp			 * so create 32-bit value from entry's range */
79633965Sjdp	{
79733965Sjdp	  eval = apply_range (e->value, e->range);
79833965Sjdp	  val &= apply_range (0xffffffff, e->range);
79933965Sjdp	}
80060484Sobrien      else if ((r->sbit == e->range.sbit && r->ebit == e->range.ebit)
80160484Sobrien	       || (e->range.sbit == 0 && e->range.ebit == 0))
80233965Sjdp	{
80333965Sjdp	  eval = apply_range (e->value, *r);
80433965Sjdp	  val = apply_range (val, *r);
80533965Sjdp	}
80633965Sjdp      else
80733965Sjdp	continue;
80833965Sjdp      if (val == eval)
80933965Sjdp	return e;
81033965Sjdp    }
81133965Sjdp  return 0;
81233965Sjdp}
81333965Sjdp
81477298Sobrien/* Return a pointer to the list of entries for a given processor and type.  */
81533965Sjdp
81633965Sjdpstatic struct itbl_entry **
81733965Sjdpget_entries (e_processor processor, e_type type)
81833965Sjdp{
81933965Sjdp  return &entries[processor][type];
82033965Sjdp}
82133965Sjdp
82277298Sobrien/* Return an integral value for the processor passed from yyparse.  */
82333965Sjdp
82477298Sobrienstatic e_processor
82533965Sjdpget_processor (int yyproc)
82633965Sjdp{
82733965Sjdp  /* translate from yacc's processor to enum */
82833965Sjdp  if (yyproc >= e_p0 && yyproc < e_nprocs)
82933965Sjdp    return (e_processor) yyproc;
83033965Sjdp  return e_invproc;		/* error; invalid processor */
83133965Sjdp}
83233965Sjdp
83377298Sobrien/* Return an integral value for the entry type passed from yyparse.  */
83433965Sjdp
83577298Sobrienstatic e_type
83633965Sjdpget_type (int yytype)
83733965Sjdp{
83833965Sjdp  switch (yytype)
83933965Sjdp    {
84033965Sjdp      /* translate from yacc's type to enum */
84133965Sjdp    case INSN:
84233965Sjdp      return e_insn;
84333965Sjdp    case DREG:
84433965Sjdp      return e_dreg;
84533965Sjdp    case CREG:
84633965Sjdp      return e_creg;
84733965Sjdp    case GREG:
84833965Sjdp      return e_greg;
84933965Sjdp    case ADDR:
85033965Sjdp      return e_addr;
85133965Sjdp    case IMMED:
85233965Sjdp      return e_immed;
85333965Sjdp    default:
85433965Sjdp      return e_invtype;		/* error; invalid type */
85533965Sjdp    }
85633965Sjdp}
85733965Sjdp
85833965Sjdp/* Allocate and initialize an entry */
85933965Sjdp
86033965Sjdpstatic struct itbl_entry *
86133965Sjdpalloc_entry (e_processor processor, e_type type,
86233965Sjdp	     char *name, unsigned long value)
86333965Sjdp{
86433965Sjdp  struct itbl_entry *e, **es;
86533965Sjdp  if (!name)
86633965Sjdp    return 0;
86733965Sjdp  e = (struct itbl_entry *) malloc (sizeof (struct itbl_entry));
86833965Sjdp  if (e)
86933965Sjdp    {
87033965Sjdp      memset (e, 0, sizeof (struct itbl_entry));
87133965Sjdp      e->name = (char *) malloc (sizeof (strlen (name)) + 1);
87233965Sjdp      if (e->name)
87333965Sjdp	strcpy (e->name, name);
87433965Sjdp      e->processor = processor;
87533965Sjdp      e->type = type;
87633965Sjdp      e->value = value;
87733965Sjdp      es = get_entries (e->processor, e->type);
87833965Sjdp      e->next = *es;
87933965Sjdp      *es = e;
88033965Sjdp    }
88133965Sjdp  return e;
88233965Sjdp}
88333965Sjdp
88433965Sjdp/* Allocate and initialize an entry's field */
88533965Sjdp
88633965Sjdpstatic struct itbl_field *
88733965Sjdpalloc_field (e_type type, int sbit, int ebit,
88833965Sjdp	     unsigned long flags)
88933965Sjdp{
89033965Sjdp  struct itbl_field *f;
89133965Sjdp  f = (struct itbl_field *) malloc (sizeof (struct itbl_field));
89233965Sjdp  if (f)
89333965Sjdp    {
89433965Sjdp      memset (f, 0, sizeof (struct itbl_field));
89533965Sjdp      f->type = type;
89633965Sjdp      f->range.sbit = sbit;
89733965Sjdp      f->range.ebit = ebit;
89833965Sjdp      f->flags = flags;
89933965Sjdp    }
90033965Sjdp  return f;
90133965Sjdp}
902