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