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