itbl-ops.c revision 77298
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
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 */
15733965Sjdpstatic unsigned long build_opcode PARAMS ((struct itbl_entry *e));
15833965Sjdpstatic e_type get_type PARAMS ((int yytype));
15933965Sjdpstatic e_processor get_processor PARAMS ((int yyproc));
16077298Sobrienstatic struct itbl_entry **get_entries PARAMS ((e_processor processor,
16133965Sjdp						e_type type));
16277298Sobrienstatic struct itbl_entry *find_entry_byname PARAMS ((e_processor processor,
16333965Sjdp					e_type type, char *name));
16477298Sobrienstatic struct itbl_entry *find_entry_byval PARAMS ((e_processor processor,
16533965Sjdp			e_type type, unsigned long val, struct itbl_range *r));
16677298Sobrienstatic struct itbl_entry *alloc_entry PARAMS ((e_processor processor,
16733965Sjdp		e_type type, char *name, unsigned long value));
16877298Sobrienstatic unsigned long apply_range PARAMS ((unsigned long value,
16933965Sjdp						struct itbl_range r));
17077298Sobrienstatic unsigned long extract_range PARAMS ((unsigned long value,
17133965Sjdp						struct itbl_range r));
17277298Sobrienstatic struct itbl_field *alloc_field PARAMS ((e_type type, int sbit,
17333965Sjdp					int ebit, unsigned long flags));
17433965Sjdp
17533965Sjdp/*======================================================================*/
17633965Sjdp/* Interfaces to the parser */
17733965Sjdp
17833965Sjdp/* Open the table and use lex and yacc to parse the entries.
17933965Sjdp * Return 1 for failure; 0 for success.  */
18033965Sjdp
18177298Sobrienint
18233965Sjdpitbl_parse (char *insntbl)
18333965Sjdp{
18433965Sjdp  extern FILE *yyin;
18533965Sjdp  extern int yyparse (void);
18633965Sjdp  yyin = fopen (insntbl, "r");
18733965Sjdp  if (yyin == 0)
18833965Sjdp    {
18933965Sjdp      printf ("Can't open processor instruction specification file \"%s\"\n",
19033965Sjdp	      insntbl);
19133965Sjdp      return 1;
19233965Sjdp    }
19333965Sjdp  else
19433965Sjdp    {
19533965Sjdp      while (yyparse ());
19633965Sjdp    }
19733965Sjdp  fclose (yyin);
19833965Sjdp  itbl_have_entries = 1;
19933965Sjdp  return 0;
20033965Sjdp}
20133965Sjdp
20233965Sjdp/* Add a register entry */
20333965Sjdp
20433965Sjdpstruct itbl_entry *
20533965Sjdpitbl_add_reg (int yyprocessor, int yytype, char *regname,
20633965Sjdp	      int regnum)
20733965Sjdp{
20877298Sobrien#if 0
20933965Sjdp#include "as.h"
21033965Sjdp#include "symbols.h"
21133965Sjdp  /* Since register names don't have a prefix, we put them in the symbol table so
21233965Sjdp     they can't be used as symbols.  This also simplifies argument parsing as
21333965Sjdp     we can let gas parse registers for us.  The recorded register number is
21433965Sjdp     regnum.  */
21533965Sjdp  /* Use symbol_create here instead of symbol_new so we don't try to
21633965Sjdp     output registers into the object file's symbol table.  */
21733965Sjdp  symbol_table_insert (symbol_create (regname, reg_section,
21833965Sjdp				      regnum, &zero_address_frag));
21933965Sjdp#endif
22033965Sjdp  return alloc_entry (get_processor (yyprocessor), get_type (yytype), regname,
22133965Sjdp		      (unsigned long) regnum);
22233965Sjdp}
22333965Sjdp
22433965Sjdp/* Add an instruction entry */
22533965Sjdp
22633965Sjdpstruct itbl_entry *
22733965Sjdpitbl_add_insn (int yyprocessor, char *name, unsigned long value,
22833965Sjdp	       int sbit, int ebit, unsigned long flags)
22933965Sjdp{
23033965Sjdp  struct itbl_entry *e;
23133965Sjdp  e = alloc_entry (get_processor (yyprocessor), e_insn, name, value);
23233965Sjdp  if (e)
23333965Sjdp    {
23433965Sjdp      e->range.sbit = sbit;
23533965Sjdp      e->range.ebit = ebit;
23633965Sjdp      e->flags = flags;
23733965Sjdp      itbl_num_opcodes++;
23833965Sjdp    }
23933965Sjdp  return e;
24033965Sjdp}
24133965Sjdp
24233965Sjdp/* Add an operand to an instruction entry */
24333965Sjdp
24433965Sjdpstruct itbl_field *
24533965Sjdpitbl_add_operand (struct itbl_entry *e, int yytype, int sbit,
24633965Sjdp		  int ebit, unsigned long flags)
24733965Sjdp{
24833965Sjdp  struct itbl_field *f, **last_f;
24933965Sjdp  if (!e)
25033965Sjdp    return 0;
25177298Sobrien  /* Add to end of fields' list.  */
25233965Sjdp  f = alloc_field (get_type (yytype), sbit, ebit, flags);
25333965Sjdp  if (f)
25433965Sjdp    {
25533965Sjdp      last_f = &e->fields;
25633965Sjdp      while (*last_f)
25733965Sjdp	last_f = &(*last_f)->next;
25833965Sjdp      *last_f = f;
25933965Sjdp      f->next = 0;
26033965Sjdp    }
26133965Sjdp  return f;
26233965Sjdp}
26333965Sjdp
26433965Sjdp/*======================================================================*/
26533965Sjdp/* Interfaces for assembler and disassembler */
26633965Sjdp
26733965Sjdp#ifndef STAND_ALONE
26833965Sjdp#include "as.h"
26933965Sjdp#include "symbols.h"
27033965Sjdpstatic void append_insns_as_macros (void);
27133965Sjdp
27277298Sobrien/* Initialize for gas.  */
27377298Sobrien
27477298Sobrienvoid
27533965Sjdpitbl_init (void)
27633965Sjdp{
27733965Sjdp  struct itbl_entry *e, **es;
27833965Sjdp  e_processor procn;
27933965Sjdp  e_type type;
28033965Sjdp
28133965Sjdp  if (!itbl_have_entries)
28277298Sobrien    return;
28333965Sjdp
28433965Sjdp  /* Since register names don't have a prefix, put them in the symbol table so
28533965Sjdp     they can't be used as symbols.  This simplifies argument parsing as
28677298Sobrien     we can let gas parse registers for us.  */
28733965Sjdp  /* Use symbol_create instead of symbol_new so we don't try to
28833965Sjdp     output registers into the object file's symbol table.  */
28933965Sjdp
29033965Sjdp  for (type = e_regtype0; type < e_nregtypes; type++)
29133965Sjdp    for (procn = e_p0; procn < e_nprocs; procn++)
29233965Sjdp      {
29333965Sjdp	es = get_entries (procn, type);
29433965Sjdp	for (e = *es; e; e = e->next)
29533965Sjdp	  {
29633965Sjdp	    symbol_table_insert (symbol_create (e->name, reg_section,
29777298Sobrien						e->value, &zero_address_frag));
29833965Sjdp	  }
29933965Sjdp      }
30033965Sjdp  append_insns_as_macros ();
30133965Sjdp}
30233965Sjdp
30377298Sobrien/* Append insns to opcodes table and increase number of opcodes
30477298Sobrien * Structure of opcodes table:
30533965Sjdp * struct itbl_opcode
30633965Sjdp * {
30733965Sjdp *   const char *name;
30877298Sobrien *   const char *args; 		- string describing the arguments.
30977298Sobrien *   unsigned long match; 	- opcode, or ISA level if pinfo=INSN_MACRO
31077298Sobrien *   unsigned long mask; 	- opcode mask, or macro id if pinfo=INSN_MACRO
31177298Sobrien *   unsigned long pinfo; 	- insn flags, or INSN_MACRO
31233965Sjdp * };
31333965Sjdp * examples:
31433965Sjdp *	{"li",      "t,i",  0x34000000, 0xffe00000, WR_t    },
31533965Sjdp *	{"li",      "t,I",  0,    (int) M_LI,   INSN_MACRO  },
31633965Sjdp */
31733965Sjdp
31833965Sjdpstatic char *form_args (struct itbl_entry *e);
31977298Sobrienstatic void
32033965Sjdpappend_insns_as_macros (void)
32133965Sjdp{
32233965Sjdp  struct ITBL_OPCODE_STRUCT *new_opcodes, *o;
32333965Sjdp  struct itbl_entry *e, **es;
32433965Sjdp  int n, id, size, new_size, new_num_opcodes;
32533965Sjdp
32633965Sjdp  if (!itbl_have_entries)
32777298Sobrien    return;
32833965Sjdp
32933965Sjdp  if (!itbl_num_opcodes)	/* no new instructions to add! */
33033965Sjdp    {
33133965Sjdp      return;
33233965Sjdp    }
33333965Sjdp  DBG (("previous num_opcodes=%d\n", ITBL_NUM_OPCODES));
33433965Sjdp
33533965Sjdp  new_num_opcodes = ITBL_NUM_OPCODES + itbl_num_opcodes;
33633965Sjdp  ASSERT (new_num_opcodes >= itbl_num_opcodes);
33733965Sjdp
33833965Sjdp  size = sizeof (struct ITBL_OPCODE_STRUCT) * ITBL_NUM_OPCODES;
33933965Sjdp  ASSERT (size >= 0);
34033965Sjdp  DBG (("I get=%d\n", size / sizeof (ITBL_OPCODES[0])));
34133965Sjdp
34233965Sjdp  new_size = sizeof (struct ITBL_OPCODE_STRUCT) * new_num_opcodes;
34333965Sjdp  ASSERT (new_size > size);
34433965Sjdp
34533965Sjdp  /* FIXME since ITBL_OPCODES culd be a static table,
34677298Sobrien		we can't realloc or delete the old memory.  */
34733965Sjdp  new_opcodes = (struct ITBL_OPCODE_STRUCT *) malloc (new_size);
34833965Sjdp  if (!new_opcodes)
34933965Sjdp    {
35060484Sobrien      printf (_("Unable to allocate memory for new instructions\n"));
35133965Sjdp      return;
35233965Sjdp    }
35333965Sjdp  if (size)			/* copy prexisting opcodes table */
35433965Sjdp    memcpy (new_opcodes, ITBL_OPCODES, size);
35533965Sjdp
35633965Sjdp  /* FIXME! some NUMOPCODES are calculated expressions.
35777298Sobrien		These need to be changed before itbls can be supported.  */
35833965Sjdp
35933965Sjdp  id = ITBL_NUM_MACROS;		/* begin the next macro id after the last */
36033965Sjdp  o = &new_opcodes[ITBL_NUM_OPCODES];	/* append macro to opcodes list */
36133965Sjdp  for (n = e_p0; n < e_nprocs; n++)
36233965Sjdp    {
36333965Sjdp      es = get_entries (n, e_insn);
36433965Sjdp      for (e = *es; e; e = e->next)
36533965Sjdp	{
36633965Sjdp	  /* name,    args,   mask,       match,  pinfo
36733965Sjdp		 * {"li",      "t,i",  0x34000000, 0xffe00000, WR_t    },
36833965Sjdp		 * {"li",      "t,I",  0,    (int) M_LI,   INSN_MACRO  },
36933965Sjdp		 * Construct args from itbl_fields.
37033965Sjdp		*/
37133965Sjdp	  o->name = e->name;
37233965Sjdp	  o->args = strdup (form_args (e));
37333965Sjdp	  o->mask = apply_range (e->value, e->range);
37433965Sjdp	  /* FIXME how to catch durring assembly? */
37533965Sjdp	  /* mask to identify this insn */
37633965Sjdp	  o->match = apply_range (e->value, e->range);
37733965Sjdp	  o->pinfo = 0;
37833965Sjdp
37933965Sjdp#ifdef USE_MACROS
38033965Sjdp	  o->mask = id++;	/* FIXME how to catch durring assembly? */
38133965Sjdp	  o->match = 0;		/* for macros, the insn_isa number */
38233965Sjdp	  o->pinfo = INSN_MACRO;
38333965Sjdp#endif
38433965Sjdp
38533965Sjdp	  /* Don't add instructions which caused an error */
38633965Sjdp	  if (o->args)
38733965Sjdp	    o++;
38833965Sjdp	  else
38933965Sjdp	    new_num_opcodes--;
39033965Sjdp	}
39133965Sjdp    }
39233965Sjdp  ITBL_OPCODES = new_opcodes;
39333965Sjdp  ITBL_NUM_OPCODES = new_num_opcodes;
39433965Sjdp
39533965Sjdp  /* FIXME
39633965Sjdp		At this point, we can free the entries, as they should have
39733965Sjdp		been added to the assembler's tables.
39833965Sjdp		Don't free name though, since name is being used by the new
39933965Sjdp		opcodes table.
40033965Sjdp
40177298Sobrien		Eventually, we should also free the new opcodes table itself
40233965Sjdp		on exit.
40333965Sjdp	*/
40433965Sjdp}
40533965Sjdp
40633965Sjdpstatic char *
40733965Sjdpform_args (struct itbl_entry *e)
40833965Sjdp{
40933965Sjdp  static char s[31];
41033965Sjdp  char c = 0, *p = s;
41133965Sjdp  struct itbl_field *f;
41233965Sjdp
41333965Sjdp  ASSERT (e);
41433965Sjdp  for (f = e->fields; f; f = f->next)
41533965Sjdp    {
41633965Sjdp      switch (f->type)
41733965Sjdp	{
41833965Sjdp	case e_dreg:
41933965Sjdp	  c = 'd';
42033965Sjdp	  break;
42133965Sjdp	case e_creg:
42233965Sjdp	  c = 't';
42333965Sjdp	  break;
42433965Sjdp	case e_greg:
42533965Sjdp	  c = 's';
42633965Sjdp	  break;
42733965Sjdp	case e_immed:
42833965Sjdp	  c = 'i';
42933965Sjdp	  break;
43033965Sjdp	case e_addr:
43133965Sjdp	  c = 'a';
43233965Sjdp	  break;
43333965Sjdp	default:
43433965Sjdp	  c = 0;		/* ignore; unknown field type */
43533965Sjdp	}
43633965Sjdp      if (c)
43733965Sjdp	{
43833965Sjdp	  if (p != s)
43933965Sjdp	    *p++ = ',';
44033965Sjdp	  *p++ = c;
44133965Sjdp	}
44233965Sjdp    }
44333965Sjdp  *p = 0;
44433965Sjdp  return s;
44533965Sjdp}
44633965Sjdp#endif /* !STAND_ALONE */
44733965Sjdp
44833965Sjdp/* Get processor's register name from val */
44933965Sjdp
45060484Sobrienint
45160484Sobrienitbl_get_reg_val (char *name, unsigned long *pval)
45233965Sjdp{
45333965Sjdp  e_type t;
45433965Sjdp  e_processor p;
45560484Sobrien
45633965Sjdp  for (p = e_p0; p < e_nprocs; p++)
45760484Sobrien    {
45860484Sobrien      for (t = e_regtype0; t < e_nregtypes; t++)
45960484Sobrien	{
46060484Sobrien	  if (itbl_get_val (p, t, name, pval))
46160484Sobrien	    return 1;
46260484Sobrien	}
46360484Sobrien    }
46433965Sjdp  return 0;
46533965Sjdp}
46633965Sjdp
46733965Sjdpchar *
46833965Sjdpitbl_get_name (e_processor processor, e_type type, unsigned long val)
46933965Sjdp{
47033965Sjdp  struct itbl_entry *r;
47133965Sjdp  /* type depends on instruction passed */
47233965Sjdp  r = find_entry_byval (processor, type, val, 0);
47333965Sjdp  if (r)
47433965Sjdp    return r->name;
47533965Sjdp  else
47633965Sjdp    return 0;			/* error; invalid operand */
47733965Sjdp}
47833965Sjdp
47933965Sjdp/* Get processor's register value from name */
48033965Sjdp
48160484Sobrienint
48260484Sobrienitbl_get_val (e_processor processor, e_type type, char *name,
48360484Sobrien	      unsigned long *pval)
48433965Sjdp{
48533965Sjdp  struct itbl_entry *r;
48633965Sjdp  /* type depends on instruction passed */
48733965Sjdp  r = find_entry_byname (processor, type, name);
48860484Sobrien  if (r == NULL)
48960484Sobrien    return 0;
49060484Sobrien  *pval = r->value;
49160484Sobrien  return 1;
49233965Sjdp}
49333965Sjdp
49433965Sjdp/* Assemble instruction "name" with operands "s".
49533965Sjdp * name - name of instruction
49633965Sjdp * s - operands
49733965Sjdp * returns - long word for assembled instruction */
49833965Sjdp
49977298Sobrienunsigned long
50033965Sjdpitbl_assemble (char *name, char *s)
50133965Sjdp{
50233965Sjdp  unsigned long opcode;
50333965Sjdp  struct itbl_entry *e;
50433965Sjdp  struct itbl_field *f;
50533965Sjdp  char *n;
50633965Sjdp  int processor;
50733965Sjdp
50833965Sjdp  if (!name || !*name)
50933965Sjdp    return 0;			/* error!  must have a opcode name/expr */
51033965Sjdp
51133965Sjdp  /* find entry in list of instructions for all processors */
51233965Sjdp  for (processor = 0; processor < e_nprocs; processor++)
51333965Sjdp    {
51433965Sjdp      e = find_entry_byname (processor, e_insn, name);
51533965Sjdp      if (e)
51633965Sjdp	break;
51733965Sjdp    }
51833965Sjdp  if (!e)
51977298Sobrien    return 0;			/* opcode not in table; invalid instruction */
52033965Sjdp  opcode = build_opcode (e);
52133965Sjdp
52233965Sjdp  /* parse opcode's args (if any) */
52377298Sobrien  for (f = e->fields; f; f = f->next)	/* for each arg, ...  */
52433965Sjdp    {
52533965Sjdp      struct itbl_entry *r;
52633965Sjdp      unsigned long value;
52733965Sjdp      if (!s || !*s)
52833965Sjdp	return 0;		/* error - not enough operands */
52933965Sjdp      n = itbl_get_field (&s);
53033965Sjdp      /* n should be in form $n or 0xhhh (are symbol names valid?? */
53133965Sjdp      switch (f->type)
53233965Sjdp	{
53333965Sjdp	case e_dreg:
53433965Sjdp	case e_creg:
53533965Sjdp	case e_greg:
53633965Sjdp	  /* Accept either a string name
53733965Sjdp			 * or '$' followed by the register number */
53833965Sjdp	  if (*n == '$')
53933965Sjdp	    {
54033965Sjdp	      n++;
54133965Sjdp	      value = strtol (n, 0, 10);
54233965Sjdp	      /* FIXME! could have "0l"... then what?? */
54333965Sjdp	      if (value == 0 && *n != '0')
54433965Sjdp		return 0;	/* error; invalid operand */
54533965Sjdp	    }
54633965Sjdp	  else
54733965Sjdp	    {
54833965Sjdp	      r = find_entry_byname (e->processor, f->type, n);
54933965Sjdp	      if (r)
55033965Sjdp		value = r->value;
55133965Sjdp	      else
55233965Sjdp		return 0;	/* error; invalid operand */
55333965Sjdp	    }
55433965Sjdp	  break;
55533965Sjdp	case e_addr:
55633965Sjdp	  /* use assembler's symbol table to find symbol */
55733965Sjdp	  /* FIXME!! Do we need this?
55833965Sjdp				if so, what about relocs??
55933965Sjdp				my_getExpression (&imm_expr, s);
56033965Sjdp				return 0;	/-* error; invalid operand *-/
56133965Sjdp				break;
56233965Sjdp			*/
56333965Sjdp	  /* If not a symbol, fall thru to IMMED */
56433965Sjdp	case e_immed:
56577298Sobrien	  if (*n == '0' && *(n + 1) == 'x')	/* hex begins 0x...  */
56633965Sjdp	    {
56733965Sjdp	      n += 2;
56833965Sjdp	      value = strtol (n, 0, 16);
56933965Sjdp	      /* FIXME! could have "0xl"... then what?? */
57033965Sjdp	    }
57133965Sjdp	  else
57233965Sjdp	    {
57333965Sjdp	      value = strtol (n, 0, 10);
57433965Sjdp	      /* FIXME! could have "0l"... then what?? */
57533965Sjdp	      if (value == 0 && *n != '0')
57633965Sjdp		return 0;	/* error; invalid operand */
57733965Sjdp	    }
57833965Sjdp	  break;
57933965Sjdp	default:
58033965Sjdp	  return 0;		/* error; invalid field spec */
58133965Sjdp	}
58233965Sjdp      opcode |= apply_range (value, f->range);
58333965Sjdp    }
58433965Sjdp  if (s && *s)
58533965Sjdp    return 0;			/* error - too many operands */
58633965Sjdp  return opcode;		/* done! */
58733965Sjdp}
58833965Sjdp
58933965Sjdp/* Disassemble instruction "insn".
59033965Sjdp * insn - instruction
59133965Sjdp * s - buffer to hold disassembled instruction
59233965Sjdp * returns - 1 if succeeded; 0 if failed
59333965Sjdp */
59433965Sjdp
59577298Sobrienint
59633965Sjdpitbl_disassemble (char *s, unsigned long insn)
59733965Sjdp{
59833965Sjdp  e_processor processor;
59933965Sjdp  struct itbl_entry *e;
60033965Sjdp  struct itbl_field *f;
60133965Sjdp
60233965Sjdp  if (!ITBL_IS_INSN (insn))
60377298Sobrien    return 0;			/* error */
60433965Sjdp  processor = get_processor (ITBL_DECODE_PNUM (insn));
60533965Sjdp
60633965Sjdp  /* find entry in list */
60733965Sjdp  e = find_entry_byval (processor, e_insn, insn, 0);
60833965Sjdp  if (!e)
60977298Sobrien    return 0;			/* opcode not in table; invalid instruction */
61033965Sjdp  strcpy (s, e->name);
61133965Sjdp
61277298Sobrien  /* Parse insn's args (if any).  */
61377298Sobrien  for (f = e->fields; f; f = f->next)	/* for each arg, ...  */
61433965Sjdp    {
61533965Sjdp      struct itbl_entry *r;
61633965Sjdp      unsigned long value;
61733965Sjdp
61877298Sobrien      if (f == e->fields)	/* First operand is preceeded by tab.  */
61933965Sjdp	strcat (s, "\t");
62077298Sobrien      else			/* ','s separate following operands.  */
62133965Sjdp	strcat (s, ",");
62233965Sjdp      value = extract_range (insn, f->range);
62333965Sjdp      /* n should be in form $n or 0xhhh (are symbol names valid?? */
62433965Sjdp      switch (f->type)
62533965Sjdp	{
62633965Sjdp	case e_dreg:
62733965Sjdp	case e_creg:
62833965Sjdp	case e_greg:
62933965Sjdp	  /* Accept either a string name
63077298Sobrien	     or '$' followed by the register number.  */
63133965Sjdp	  r = find_entry_byval (e->processor, f->type, value, &f->range);
63233965Sjdp	  if (r)
63333965Sjdp	    strcat (s, r->name);
63433965Sjdp	  else
63560484Sobrien	    sprintf (s, "%s$%lu", s, value);
63633965Sjdp	  break;
63733965Sjdp	case e_addr:
63877298Sobrien	  /* Use assembler's symbol table to find symbol.  */
63977298Sobrien	  /* FIXME!! Do we need this?  If so, what about relocs??  */
64077298Sobrien	  /* If not a symbol, fall through to IMMED.  */
64133965Sjdp	case e_immed:
64260484Sobrien	  sprintf (s, "%s0x%lx", s, value);
64333965Sjdp	  break;
64433965Sjdp	default:
64533965Sjdp	  return 0;		/* error; invalid field spec */
64633965Sjdp	}
64733965Sjdp    }
64877298Sobrien  return 1;			/* Done!  */
64933965Sjdp}
65033965Sjdp
65133965Sjdp/*======================================================================*/
65233965Sjdp/*
65333965Sjdp * Local functions for manipulating private structures containing
65433965Sjdp * the names and format for the new instructions and registers
65533965Sjdp * for each processor.
65633965Sjdp */
65733965Sjdp
65833965Sjdp/* Calculate instruction's opcode and function values from entry */
65933965Sjdp
66077298Sobrienstatic unsigned long
66133965Sjdpbuild_opcode (struct itbl_entry *e)
66233965Sjdp{
66333965Sjdp  unsigned long opcode;
66433965Sjdp
66533965Sjdp  opcode = apply_range (e->value, e->range);
66633965Sjdp  opcode |= ITBL_ENCODE_PNUM (e->processor);
66733965Sjdp  return opcode;
66833965Sjdp}
66933965Sjdp
67033965Sjdp/* Calculate absolute value given the relative value and bit position range
67133965Sjdp * within the instruction.
67233965Sjdp * The range is inclusive where 0 is least significant bit.
67333965Sjdp * A range of { 24, 20 } will have a mask of
67433965Sjdp * bit   3           2            1
67533965Sjdp * pos: 1098 7654 3210 9876 5432 1098 7654 3210
67633965Sjdp * bin: 0000 0001 1111 0000 0000 0000 0000 0000
67733965Sjdp * hex:    0    1    f    0    0    0    0    0
67833965Sjdp * mask: 0x01f00000.
67933965Sjdp */
68033965Sjdp
68177298Sobrienstatic unsigned long
68233965Sjdpapply_range (unsigned long rval, struct itbl_range r)
68333965Sjdp{
68433965Sjdp  unsigned long mask;
68533965Sjdp  unsigned long aval;
68633965Sjdp  int len = MAX_BITPOS - r.sbit;
68733965Sjdp
68833965Sjdp  ASSERT (r.sbit >= r.ebit);
68933965Sjdp  ASSERT (MAX_BITPOS >= r.sbit);
69033965Sjdp  ASSERT (r.ebit >= 0);
69133965Sjdp
69233965Sjdp  /* create mask by truncating 1s by shifting */
69333965Sjdp  mask = 0xffffffff << len;
69433965Sjdp  mask = mask >> len;
69533965Sjdp  mask = mask >> r.ebit;
69633965Sjdp  mask = mask << r.ebit;
69733965Sjdp
69833965Sjdp  aval = (rval << r.ebit) & mask;
69933965Sjdp  return aval;
70033965Sjdp}
70133965Sjdp
70233965Sjdp/* Calculate relative value given the absolute value and bit position range
70333965Sjdp * within the instruction.  */
70433965Sjdp
70577298Sobrienstatic unsigned long
70633965Sjdpextract_range (unsigned long aval, struct itbl_range r)
70733965Sjdp{
70833965Sjdp  unsigned long mask;
70933965Sjdp  unsigned long rval;
71033965Sjdp  int len = MAX_BITPOS - r.sbit;
71133965Sjdp
71233965Sjdp  /* create mask by truncating 1s by shifting */
71333965Sjdp  mask = 0xffffffff << len;
71433965Sjdp  mask = mask >> len;
71533965Sjdp  mask = mask >> r.ebit;
71633965Sjdp  mask = mask << r.ebit;
71733965Sjdp
71833965Sjdp  rval = (aval & mask) >> r.ebit;
71933965Sjdp  return rval;
72033965Sjdp}
72133965Sjdp
72233965Sjdp/* Extract processor's assembly instruction field name from s;
72333965Sjdp * forms are "n args" "n,args" or "n" */
72433965Sjdp/* Return next argument from string pointer "s" and advance s.
72560484Sobrien * delimiters are " ,()" */
72633965Sjdp
72733965Sjdpchar *
72833965Sjdpitbl_get_field (char **S)
72933965Sjdp{
73033965Sjdp  static char n[128];
73160484Sobrien  char *s;
73233965Sjdp  int len;
73333965Sjdp
73433965Sjdp  s = *S;
73533965Sjdp  if (!s || !*s)
73633965Sjdp    return 0;
73760484Sobrien  /* FIXME: This is a weird set of delimiters.  */
73860484Sobrien  len = strcspn (s, " \t,()");
73933965Sjdp  ASSERT (128 > len + 1);
74033965Sjdp  strncpy (n, s, len);
74133965Sjdp  n[len] = 0;
74233965Sjdp  if (s[len] == '\0')
74333965Sjdp    s = 0;			/* no more args */
74433965Sjdp  else
74533965Sjdp    s += len + 1;		/* advance to next arg */
74633965Sjdp
74733965Sjdp  *S = s;
74833965Sjdp  return n;
74933965Sjdp}
75033965Sjdp
75133965Sjdp/* Search entries for a given processor and type
75233965Sjdp * to find one matching the name "n".
75333965Sjdp * Return a pointer to the entry */
75433965Sjdp
75533965Sjdpstatic struct itbl_entry *
75633965Sjdpfind_entry_byname (e_processor processor,
75733965Sjdp		   e_type type, char *n)
75833965Sjdp{
75933965Sjdp  struct itbl_entry *e, **es;
76033965Sjdp
76133965Sjdp  es = get_entries (processor, type);
76277298Sobrien  for (e = *es; e; e = e->next)	/* for each entry, ...  */
76333965Sjdp    {
76433965Sjdp      if (!strcmp (e->name, n))
76533965Sjdp	return e;
76633965Sjdp    }
76733965Sjdp  return 0;
76833965Sjdp}
76933965Sjdp
77033965Sjdp/* Search entries for a given processor and type
77133965Sjdp * to find one matching the value "val" for the range "r".
77233965Sjdp * Return a pointer to the entry.
77333965Sjdp * This function is used for disassembling fields of an instruction.
77433965Sjdp */
77533965Sjdp
77633965Sjdpstatic struct itbl_entry *
77733965Sjdpfind_entry_byval (e_processor processor, e_type type,
77833965Sjdp		  unsigned long val, struct itbl_range *r)
77933965Sjdp{
78033965Sjdp  struct itbl_entry *e, **es;
78133965Sjdp  unsigned long eval;
78233965Sjdp
78333965Sjdp  es = get_entries (processor, type);
78477298Sobrien  for (e = *es; e; e = e->next)	/* for each entry, ...  */
78533965Sjdp    {
78633965Sjdp      if (processor != e->processor)
78733965Sjdp	continue;
78833965Sjdp      /* For insns, we might not know the range of the opcode,
78933965Sjdp	 * so a range of 0 will allow this routine to match against
79033965Sjdp	 * the range of the entry to be compared with.
79133965Sjdp	 * This could cause ambiguities.
79233965Sjdp	 * For operands, we get an extracted value and a range.
79333965Sjdp	 */
79477298Sobrien      /* if range is 0, mask val against the range of the compared entry.  */
79533965Sjdp      if (r == 0)		/* if no range passed, must be whole 32-bits
79633965Sjdp			 * so create 32-bit value from entry's range */
79733965Sjdp	{
79833965Sjdp	  eval = apply_range (e->value, e->range);
79933965Sjdp	  val &= apply_range (0xffffffff, e->range);
80033965Sjdp	}
80160484Sobrien      else if ((r->sbit == e->range.sbit && r->ebit == e->range.ebit)
80260484Sobrien	       || (e->range.sbit == 0 && e->range.ebit == 0))
80333965Sjdp	{
80433965Sjdp	  eval = apply_range (e->value, *r);
80533965Sjdp	  val = apply_range (val, *r);
80633965Sjdp	}
80733965Sjdp      else
80833965Sjdp	continue;
80933965Sjdp      if (val == eval)
81033965Sjdp	return e;
81133965Sjdp    }
81233965Sjdp  return 0;
81333965Sjdp}
81433965Sjdp
81577298Sobrien/* Return a pointer to the list of entries for a given processor and type.  */
81633965Sjdp
81733965Sjdpstatic struct itbl_entry **
81833965Sjdpget_entries (e_processor processor, e_type type)
81933965Sjdp{
82033965Sjdp  return &entries[processor][type];
82133965Sjdp}
82233965Sjdp
82377298Sobrien/* Return an integral value for the processor passed from yyparse.  */
82433965Sjdp
82577298Sobrienstatic e_processor
82633965Sjdpget_processor (int yyproc)
82733965Sjdp{
82833965Sjdp  /* translate from yacc's processor to enum */
82933965Sjdp  if (yyproc >= e_p0 && yyproc < e_nprocs)
83033965Sjdp    return (e_processor) yyproc;
83133965Sjdp  return e_invproc;		/* error; invalid processor */
83233965Sjdp}
83333965Sjdp
83477298Sobrien/* Return an integral value for the entry type passed from yyparse.  */
83533965Sjdp
83677298Sobrienstatic e_type
83733965Sjdpget_type (int yytype)
83833965Sjdp{
83933965Sjdp  switch (yytype)
84033965Sjdp    {
84133965Sjdp      /* translate from yacc's type to enum */
84233965Sjdp    case INSN:
84333965Sjdp      return e_insn;
84433965Sjdp    case DREG:
84533965Sjdp      return e_dreg;
84633965Sjdp    case CREG:
84733965Sjdp      return e_creg;
84833965Sjdp    case GREG:
84933965Sjdp      return e_greg;
85033965Sjdp    case ADDR:
85133965Sjdp      return e_addr;
85233965Sjdp    case IMMED:
85333965Sjdp      return e_immed;
85433965Sjdp    default:
85533965Sjdp      return e_invtype;		/* error; invalid type */
85633965Sjdp    }
85733965Sjdp}
85833965Sjdp
85933965Sjdp/* Allocate and initialize an entry */
86033965Sjdp
86133965Sjdpstatic struct itbl_entry *
86233965Sjdpalloc_entry (e_processor processor, e_type type,
86333965Sjdp	     char *name, unsigned long value)
86433965Sjdp{
86533965Sjdp  struct itbl_entry *e, **es;
86633965Sjdp  if (!name)
86733965Sjdp    return 0;
86833965Sjdp  e = (struct itbl_entry *) malloc (sizeof (struct itbl_entry));
86933965Sjdp  if (e)
87033965Sjdp    {
87133965Sjdp      memset (e, 0, sizeof (struct itbl_entry));
87233965Sjdp      e->name = (char *) malloc (sizeof (strlen (name)) + 1);
87333965Sjdp      if (e->name)
87433965Sjdp	strcpy (e->name, name);
87533965Sjdp      e->processor = processor;
87633965Sjdp      e->type = type;
87733965Sjdp      e->value = value;
87833965Sjdp      es = get_entries (e->processor, e->type);
87933965Sjdp      e->next = *es;
88033965Sjdp      *es = e;
88133965Sjdp    }
88233965Sjdp  return e;
88333965Sjdp}
88433965Sjdp
88533965Sjdp/* Allocate and initialize an entry's field */
88633965Sjdp
88733965Sjdpstatic struct itbl_field *
88833965Sjdpalloc_field (e_type type, int sbit, int ebit,
88933965Sjdp	     unsigned long flags)
89033965Sjdp{
89133965Sjdp  struct itbl_field *f;
89233965Sjdp  f = (struct itbl_field *) malloc (sizeof (struct itbl_field));
89333965Sjdp  if (f)
89433965Sjdp    {
89533965Sjdp      memset (f, 0, sizeof (struct itbl_field));
89633965Sjdp      f->type = type;
89733965Sjdp      f->range.sbit = sbit;
89833965Sjdp      f->range.ebit = ebit;
89933965Sjdp      f->flags = flags;
90033965Sjdp    }
90133965Sjdp  return f;
90233965Sjdp}
903