1ed0d50c3Schristos /* itbl-ops.c
2*b88e3e88Schristos Copyright (C) 1997-2020 Free Software Foundation, Inc.
3ed0d50c3Schristos
4ed0d50c3Schristos This file is part of GAS, the GNU Assembler.
5ed0d50c3Schristos
6ed0d50c3Schristos GAS is free software; you can redistribute it and/or modify
7ed0d50c3Schristos it under the terms of the GNU General Public License as published by
8ed0d50c3Schristos the Free Software Foundation; either version 3, or (at your option)
9ed0d50c3Schristos any later version.
10ed0d50c3Schristos
11ed0d50c3Schristos GAS is distributed in the hope that it will be useful,
12ed0d50c3Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
13ed0d50c3Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14ed0d50c3Schristos GNU General Public License for more details.
15ed0d50c3Schristos
16ed0d50c3Schristos You should have received a copy of the GNU General Public License
17ed0d50c3Schristos along with GAS; see the file COPYING. If not, write to the Free
18ed0d50c3Schristos Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19ed0d50c3Schristos 02110-1301, USA. */
20ed0d50c3Schristos
21ed0d50c3Schristos /*======================================================================*/
22ed0d50c3Schristos /*
23ed0d50c3Schristos * Herein lies the support for dynamic specification of processor
24ed0d50c3Schristos * instructions and registers. Mnemonics, values, and formats for each
25ed0d50c3Schristos * instruction and register are specified in an ascii file consisting of
26ed0d50c3Schristos * table entries. The grammar for the table is defined in the document
27ed0d50c3Schristos * "Processor instruction table specification".
28ed0d50c3Schristos *
29ed0d50c3Schristos * Instructions use the gnu assembler syntax, with the addition of
30ed0d50c3Schristos * allowing mnemonics for register.
31ed0d50c3Schristos * Eg. "func $2,reg3,0x100,symbol ; comment"
32ed0d50c3Schristos * func - opcode name
33ed0d50c3Schristos * $n - register n
34ed0d50c3Schristos * reg3 - mnemonic for processor's register defined in table
35ed0d50c3Schristos * 0xddd..d - immediate value
36ed0d50c3Schristos * symbol - address of label or external symbol
37ed0d50c3Schristos *
38ed0d50c3Schristos * First, itbl_parse reads in the table of register and instruction
39ed0d50c3Schristos * names and formats, and builds a list of entries for each
40ed0d50c3Schristos * processor/type combination. lex and yacc are used to parse
41ed0d50c3Schristos * the entries in the table and call functions defined here to
42ed0d50c3Schristos * add each entry to our list.
43ed0d50c3Schristos *
44ed0d50c3Schristos * Then, when assembling or disassembling, these functions are called to
45ed0d50c3Schristos * 1) get information on a processor's registers and
46ed0d50c3Schristos * 2) assemble/disassemble an instruction.
47ed0d50c3Schristos * To assemble(disassemble) an instruction, the function
48ed0d50c3Schristos * itbl_assemble(itbl_disassemble) is called to search the list of
49ed0d50c3Schristos * instruction entries, and if a match is found, uses the format
50ed0d50c3Schristos * described in the instruction entry structure to complete the action.
51ed0d50c3Schristos *
52ed0d50c3Schristos * Eg. Suppose we have a Mips coprocessor "cop3" with data register "d2"
53ed0d50c3Schristos * and we want to define function "pig" which takes two operands.
54ed0d50c3Schristos *
55ed0d50c3Schristos * Given the table entries:
56ed0d50c3Schristos * "p3 insn pig 0x1:24-21 dreg:20-16 immed:15-0"
57ed0d50c3Schristos * "p3 dreg d2 0x2"
58ed0d50c3Schristos * and that the instruction encoding for coprocessor pz has encoding:
59ed0d50c3Schristos * #define MIPS_ENCODE_COP_NUM(z) ((0x21|(z<<1))<<25)
60ed0d50c3Schristos * #define ITBL_ENCODE_PNUM(pnum) MIPS_ENCODE_COP_NUM(pnum)
61ed0d50c3Schristos *
62ed0d50c3Schristos * a structure to describe the instruction might look something like:
63ed0d50c3Schristos * struct itbl_entry = {
64ed0d50c3Schristos * e_processor processor = e_p3
65ed0d50c3Schristos * e_type type = e_insn
66ed0d50c3Schristos * char *name = "pig"
67ed0d50c3Schristos * uint value = 0x1
68ed0d50c3Schristos * uint flags = 0
69ed0d50c3Schristos * struct itbl_range range = 24-21
70ed0d50c3Schristos * struct itbl_field *field = {
71ed0d50c3Schristos * e_type type = e_dreg
72ed0d50c3Schristos * struct itbl_range range = 20-16
73ed0d50c3Schristos * struct itbl_field *next = {
74ed0d50c3Schristos * e_type type = e_immed
75ed0d50c3Schristos * struct itbl_range range = 15-0
76ed0d50c3Schristos * struct itbl_field *next = 0
77ed0d50c3Schristos * };
78ed0d50c3Schristos * };
79ed0d50c3Schristos * struct itbl_entry *next = 0
80ed0d50c3Schristos * };
81ed0d50c3Schristos *
82ed0d50c3Schristos * And the assembler instructions:
83ed0d50c3Schristos * "pig d2,0x100"
84ed0d50c3Schristos * "pig $2,0x100"
85ed0d50c3Schristos *
86ed0d50c3Schristos * would both assemble to the hex value:
87ed0d50c3Schristos * "0x4e220100"
88ed0d50c3Schristos *
89ed0d50c3Schristos */
90ed0d50c3Schristos
91ed0d50c3Schristos #include "as.h"
92ed0d50c3Schristos #include "itbl-ops.h"
93ed0d50c3Schristos #include <itbl-parse.h>
94ed0d50c3Schristos
95ed0d50c3Schristos /* #define DEBUG */
96ed0d50c3Schristos
97ed0d50c3Schristos #ifdef DEBUG
98ed0d50c3Schristos #include <assert.h>
99ed0d50c3Schristos #define ASSERT(x) gas_assert (x)
100ed0d50c3Schristos #define DBG(x) printf x
101ed0d50c3Schristos #else
102ed0d50c3Schristos #define ASSERT(x)
103ed0d50c3Schristos #define DBG(x)
104ed0d50c3Schristos #endif
105ed0d50c3Schristos
106ed0d50c3Schristos #ifndef min
107ed0d50c3Schristos #define min(a,b) (a<b?a:b)
108ed0d50c3Schristos #endif
109ed0d50c3Schristos
110ed0d50c3Schristos int itbl_have_entries = 0;
111ed0d50c3Schristos
112ed0d50c3Schristos /*======================================================================*/
113ed0d50c3Schristos /* structures for keeping itbl format entries */
114ed0d50c3Schristos
115ed0d50c3Schristos struct itbl_range {
116ed0d50c3Schristos int sbit; /* mask starting bit position */
117ed0d50c3Schristos int ebit; /* mask ending bit position */
118ed0d50c3Schristos };
119ed0d50c3Schristos
120ed0d50c3Schristos struct itbl_field {
121ed0d50c3Schristos e_type type; /* dreg/creg/greg/immed/symb */
122ed0d50c3Schristos struct itbl_range range; /* field's bitfield range within instruction */
123ed0d50c3Schristos unsigned long flags; /* field flags */
124ed0d50c3Schristos struct itbl_field *next; /* next field in list */
125ed0d50c3Schristos };
126ed0d50c3Schristos
127ed0d50c3Schristos /* These structures define the instructions and registers for a processor.
128ed0d50c3Schristos * If the type is an instruction, the structure defines the format of an
129ed0d50c3Schristos * instruction where the fields are the list of operands.
130ed0d50c3Schristos * The flags field below uses the same values as those defined in the
131ed0d50c3Schristos * gnu assembler and are machine specific. */
132ed0d50c3Schristos struct itbl_entry {
133ed0d50c3Schristos e_processor processor; /* processor number */
134ed0d50c3Schristos e_type type; /* dreg/creg/greg/insn */
13506324dcfSchristos char *name; /* mnemonic name for insn/register */
136ed0d50c3Schristos unsigned long value; /* opcode/instruction mask/register number */
137ed0d50c3Schristos unsigned long flags; /* effects of the instruction */
138ed0d50c3Schristos struct itbl_range range; /* bit range within instruction for value */
139ed0d50c3Schristos struct itbl_field *fields; /* list of operand definitions (if any) */
140ed0d50c3Schristos struct itbl_entry *next; /* next entry */
141ed0d50c3Schristos };
142ed0d50c3Schristos
143ed0d50c3Schristos /* local data and structures */
144ed0d50c3Schristos
145ed0d50c3Schristos static int itbl_num_opcodes = 0;
146ed0d50c3Schristos /* Array of entries for each processor and entry type */
147ed0d50c3Schristos static struct itbl_entry *entries[e_nprocs][e_ntypes];
148ed0d50c3Schristos
149ed0d50c3Schristos /* local prototypes */
150ed0d50c3Schristos static unsigned long build_opcode (struct itbl_entry *e);
151ed0d50c3Schristos static e_type get_type (int yytype);
152ed0d50c3Schristos static e_processor get_processor (int yyproc);
153ed0d50c3Schristos static struct itbl_entry **get_entries (e_processor processor,
154ed0d50c3Schristos e_type type);
155ed0d50c3Schristos static struct itbl_entry *find_entry_byname (e_processor processor,
156ed0d50c3Schristos e_type type, char *name);
157ed0d50c3Schristos static struct itbl_entry *find_entry_byval (e_processor processor,
158ed0d50c3Schristos e_type type, unsigned long val, struct itbl_range *r);
159ed0d50c3Schristos static struct itbl_entry *alloc_entry (e_processor processor,
160ed0d50c3Schristos e_type type, char *name, unsigned long value);
161ed0d50c3Schristos static unsigned long apply_range (unsigned long value, struct itbl_range r);
162ed0d50c3Schristos static unsigned long extract_range (unsigned long value, struct itbl_range r);
163ed0d50c3Schristos static struct itbl_field *alloc_field (e_type type, int sbit,
164ed0d50c3Schristos int ebit, unsigned long flags);
165ed0d50c3Schristos
166ed0d50c3Schristos /*======================================================================*/
167ed0d50c3Schristos /* Interfaces to the parser */
168ed0d50c3Schristos
169ed0d50c3Schristos /* Open the table and use lex and yacc to parse the entries.
170ed0d50c3Schristos * Return 1 for failure; 0 for success. */
171ed0d50c3Schristos
172ed0d50c3Schristos int
itbl_parse(char * insntbl)173ed0d50c3Schristos itbl_parse (char *insntbl)
174ed0d50c3Schristos {
175ed0d50c3Schristos extern FILE *yyin;
176ed0d50c3Schristos extern int yyparse (void);
177ed0d50c3Schristos
178ed0d50c3Schristos yyin = fopen (insntbl, FOPEN_RT);
179ed0d50c3Schristos if (yyin == 0)
180ed0d50c3Schristos {
181ed0d50c3Schristos printf ("Can't open processor instruction specification file \"%s\"\n",
182ed0d50c3Schristos insntbl);
183ed0d50c3Schristos return 1;
184ed0d50c3Schristos }
185ed0d50c3Schristos
186ed0d50c3Schristos while (yyparse ())
187ed0d50c3Schristos ;
188ed0d50c3Schristos
189ed0d50c3Schristos fclose (yyin);
190ed0d50c3Schristos itbl_have_entries = 1;
191ed0d50c3Schristos return 0;
192ed0d50c3Schristos }
193ed0d50c3Schristos
194ed0d50c3Schristos /* Add a register entry */
195ed0d50c3Schristos
196ed0d50c3Schristos struct itbl_entry *
itbl_add_reg(int yyprocessor,int yytype,char * regname,int regnum)197ed0d50c3Schristos itbl_add_reg (int yyprocessor, int yytype, char *regname,
198ed0d50c3Schristos int regnum)
199ed0d50c3Schristos {
200ed0d50c3Schristos return alloc_entry (get_processor (yyprocessor), get_type (yytype), regname,
201ed0d50c3Schristos (unsigned long) regnum);
202ed0d50c3Schristos }
203ed0d50c3Schristos
204ed0d50c3Schristos /* Add an instruction entry */
205ed0d50c3Schristos
206ed0d50c3Schristos struct itbl_entry *
itbl_add_insn(int yyprocessor,char * name,unsigned long value,int sbit,int ebit,unsigned long flags)207ed0d50c3Schristos itbl_add_insn (int yyprocessor, char *name, unsigned long value,
208ed0d50c3Schristos int sbit, int ebit, unsigned long flags)
209ed0d50c3Schristos {
210ed0d50c3Schristos struct itbl_entry *e;
211ed0d50c3Schristos e = alloc_entry (get_processor (yyprocessor), e_insn, name, value);
212ed0d50c3Schristos if (e)
213ed0d50c3Schristos {
214ed0d50c3Schristos e->range.sbit = sbit;
215ed0d50c3Schristos e->range.ebit = ebit;
216ed0d50c3Schristos e->flags = flags;
217ed0d50c3Schristos itbl_num_opcodes++;
218ed0d50c3Schristos }
219ed0d50c3Schristos return e;
220ed0d50c3Schristos }
221ed0d50c3Schristos
222ed0d50c3Schristos /* Add an operand to an instruction entry */
223ed0d50c3Schristos
224ed0d50c3Schristos struct itbl_field *
itbl_add_operand(struct itbl_entry * e,int yytype,int sbit,int ebit,unsigned long flags)225ed0d50c3Schristos itbl_add_operand (struct itbl_entry *e, int yytype, int sbit,
226ed0d50c3Schristos int ebit, unsigned long flags)
227ed0d50c3Schristos {
228ed0d50c3Schristos struct itbl_field *f, **last_f;
229ed0d50c3Schristos if (!e)
230ed0d50c3Schristos return 0;
231ed0d50c3Schristos /* Add to end of fields' list. */
232ed0d50c3Schristos f = alloc_field (get_type (yytype), sbit, ebit, flags);
233ed0d50c3Schristos if (f)
234ed0d50c3Schristos {
235ed0d50c3Schristos last_f = &e->fields;
236ed0d50c3Schristos while (*last_f)
237ed0d50c3Schristos last_f = &(*last_f)->next;
238ed0d50c3Schristos *last_f = f;
239ed0d50c3Schristos f->next = 0;
240ed0d50c3Schristos }
241ed0d50c3Schristos return f;
242ed0d50c3Schristos }
243ed0d50c3Schristos
244ed0d50c3Schristos /*======================================================================*/
245ed0d50c3Schristos /* Interfaces for assembler and disassembler */
246ed0d50c3Schristos
247ed0d50c3Schristos #ifndef STAND_ALONE
248ed0d50c3Schristos static void append_insns_as_macros (void);
249ed0d50c3Schristos
250ed0d50c3Schristos /* Initialize for gas. */
251ed0d50c3Schristos
252ed0d50c3Schristos void
itbl_init(void)253ed0d50c3Schristos itbl_init (void)
254ed0d50c3Schristos {
255ed0d50c3Schristos struct itbl_entry *e, **es;
256ed0d50c3Schristos e_processor procn;
257ed0d50c3Schristos e_type type;
258ed0d50c3Schristos
259ed0d50c3Schristos if (!itbl_have_entries)
260ed0d50c3Schristos return;
261ed0d50c3Schristos
262ed0d50c3Schristos /* Since register names don't have a prefix, put them in the symbol table so
263ed0d50c3Schristos they can't be used as symbols. This simplifies argument parsing as
264ed0d50c3Schristos we can let gas parse registers for us. */
265ed0d50c3Schristos /* Use symbol_create instead of symbol_new so we don't try to
266ed0d50c3Schristos output registers into the object file's symbol table. */
267ed0d50c3Schristos
268ed0d50c3Schristos for (type = e_regtype0; type < e_nregtypes; type++)
269ed0d50c3Schristos for (procn = e_p0; procn < e_nprocs; procn++)
270ed0d50c3Schristos {
271ed0d50c3Schristos es = get_entries (procn, type);
272ed0d50c3Schristos for (e = *es; e; e = e->next)
273ed0d50c3Schristos {
274ed0d50c3Schristos symbol_table_insert (symbol_create (e->name, reg_section,
275ed0d50c3Schristos e->value, &zero_address_frag));
276ed0d50c3Schristos }
277ed0d50c3Schristos }
278ed0d50c3Schristos append_insns_as_macros ();
279ed0d50c3Schristos }
280ed0d50c3Schristos
281ed0d50c3Schristos /* Append insns to opcodes table and increase number of opcodes
282ed0d50c3Schristos * Structure of opcodes table:
283ed0d50c3Schristos * struct itbl_opcode
284ed0d50c3Schristos * {
285ed0d50c3Schristos * const char *name;
286ed0d50c3Schristos * const char *args; - string describing the arguments.
287ed0d50c3Schristos * unsigned long match; - opcode, or ISA level if pinfo=INSN_MACRO
288ed0d50c3Schristos * unsigned long mask; - opcode mask, or macro id if pinfo=INSN_MACRO
289ed0d50c3Schristos * unsigned long pinfo; - insn flags, or INSN_MACRO
290ed0d50c3Schristos * };
291ed0d50c3Schristos * examples:
292ed0d50c3Schristos * {"li", "t,i", 0x34000000, 0xffe00000, WR_t },
293ed0d50c3Schristos * {"li", "t,I", 0, (int) M_LI, INSN_MACRO },
294ed0d50c3Schristos */
295ed0d50c3Schristos
296ed0d50c3Schristos static char *form_args (struct itbl_entry *e);
297ed0d50c3Schristos static void
append_insns_as_macros(void)298ed0d50c3Schristos append_insns_as_macros (void)
299ed0d50c3Schristos {
300ed0d50c3Schristos struct ITBL_OPCODE_STRUCT *new_opcodes, *o;
301ed0d50c3Schristos struct itbl_entry *e, **es;
302ed0d50c3Schristos int n, size, new_num_opcodes;
303ed0d50c3Schristos #ifdef USE_MACROS
304ed0d50c3Schristos int id;
305ed0d50c3Schristos #endif
306ed0d50c3Schristos
307ed0d50c3Schristos if (!itbl_have_entries)
308ed0d50c3Schristos return;
309ed0d50c3Schristos
310ed0d50c3Schristos if (!itbl_num_opcodes) /* no new instructions to add! */
311ed0d50c3Schristos {
312ed0d50c3Schristos return;
313ed0d50c3Schristos }
314ed0d50c3Schristos DBG (("previous num_opcodes=%d\n", ITBL_NUM_OPCODES));
315ed0d50c3Schristos
316ed0d50c3Schristos new_num_opcodes = ITBL_NUM_OPCODES + itbl_num_opcodes;
317ed0d50c3Schristos ASSERT (new_num_opcodes >= itbl_num_opcodes);
318ed0d50c3Schristos
319ed0d50c3Schristos size = sizeof (struct ITBL_OPCODE_STRUCT) * ITBL_NUM_OPCODES;
320ed0d50c3Schristos ASSERT (size >= 0);
321ed0d50c3Schristos DBG (("I get=%d\n", size / sizeof (ITBL_OPCODES[0])));
322ed0d50c3Schristos
32306324dcfSchristos /* FIXME since ITBL_OPCODES could be a static table,
324ed0d50c3Schristos we can't realloc or delete the old memory. */
325ed0d50c3Schristos new_opcodes = XNEWVEC (struct ITBL_OPCODE_STRUCT, new_num_opcodes);
326ed0d50c3Schristos if (!new_opcodes)
327ed0d50c3Schristos {
328ed0d50c3Schristos printf (_("Unable to allocate memory for new instructions\n"));
329ed0d50c3Schristos return;
330ed0d50c3Schristos }
331ed0d50c3Schristos if (size) /* copy preexisting opcodes table */
332ed0d50c3Schristos memcpy (new_opcodes, ITBL_OPCODES, size);
333ed0d50c3Schristos
334ed0d50c3Schristos /* FIXME! some NUMOPCODES are calculated expressions.
335ed0d50c3Schristos These need to be changed before itbls can be supported. */
336ed0d50c3Schristos
337ed0d50c3Schristos #ifdef USE_MACROS
338ed0d50c3Schristos id = ITBL_NUM_MACROS; /* begin the next macro id after the last */
339ed0d50c3Schristos #endif
340ed0d50c3Schristos o = &new_opcodes[ITBL_NUM_OPCODES]; /* append macro to opcodes list */
341ed0d50c3Schristos for (n = e_p0; n < e_nprocs; n++)
342ed0d50c3Schristos {
343ed0d50c3Schristos es = get_entries (n, e_insn);
344ed0d50c3Schristos for (e = *es; e; e = e->next)
345ed0d50c3Schristos {
346ed0d50c3Schristos /* name, args, mask, match, pinfo
347ed0d50c3Schristos * {"li", "t,i", 0x34000000, 0xffe00000, WR_t },
348ed0d50c3Schristos * {"li", "t,I", 0, (int) M_LI, INSN_MACRO },
349ed0d50c3Schristos * Construct args from itbl_fields.
350ed0d50c3Schristos */
351ed0d50c3Schristos o->name = e->name;
352ed0d50c3Schristos o->args = strdup (form_args (e));
353ed0d50c3Schristos o->mask = apply_range (e->value, e->range);
354ed0d50c3Schristos /* FIXME how to catch during assembly? */
355ed0d50c3Schristos /* mask to identify this insn */
356ed0d50c3Schristos o->match = apply_range (e->value, e->range);
357ed0d50c3Schristos o->pinfo = 0;
358ed0d50c3Schristos
359ed0d50c3Schristos #ifdef USE_MACROS
360ed0d50c3Schristos o->mask = id++; /* FIXME how to catch during assembly? */
361ed0d50c3Schristos o->match = 0; /* for macros, the insn_isa number */
362ed0d50c3Schristos o->pinfo = INSN_MACRO;
363ed0d50c3Schristos #endif
364ed0d50c3Schristos
365ed0d50c3Schristos /* Don't add instructions which caused an error */
366ed0d50c3Schristos if (o->args)
367ed0d50c3Schristos o++;
368ed0d50c3Schristos else
369ed0d50c3Schristos new_num_opcodes--;
370ed0d50c3Schristos }
371ed0d50c3Schristos }
372ed0d50c3Schristos ITBL_OPCODES = new_opcodes;
373ed0d50c3Schristos ITBL_NUM_OPCODES = new_num_opcodes;
374ed0d50c3Schristos
375ed0d50c3Schristos /* FIXME
376ed0d50c3Schristos At this point, we can free the entries, as they should have
377ed0d50c3Schristos been added to the assembler's tables.
378ed0d50c3Schristos Don't free name though, since name is being used by the new
379ed0d50c3Schristos opcodes table.
380ed0d50c3Schristos
381ed0d50c3Schristos Eventually, we should also free the new opcodes table itself
382ed0d50c3Schristos on exit.
383ed0d50c3Schristos */
384ed0d50c3Schristos }
385ed0d50c3Schristos
386ed0d50c3Schristos static char *
form_args(struct itbl_entry * e)387ed0d50c3Schristos form_args (struct itbl_entry *e)
388ed0d50c3Schristos {
389ed0d50c3Schristos static char s[31];
390ed0d50c3Schristos char c = 0, *p = s;
391ed0d50c3Schristos struct itbl_field *f;
392ed0d50c3Schristos
393ed0d50c3Schristos ASSERT (e);
394ed0d50c3Schristos for (f = e->fields; f; f = f->next)
395ed0d50c3Schristos {
396ed0d50c3Schristos switch (f->type)
397ed0d50c3Schristos {
398ed0d50c3Schristos case e_dreg:
399ed0d50c3Schristos c = 'd';
400ed0d50c3Schristos break;
401ed0d50c3Schristos case e_creg:
402ed0d50c3Schristos c = 't';
403ed0d50c3Schristos break;
404ed0d50c3Schristos case e_greg:
405ed0d50c3Schristos c = 's';
406ed0d50c3Schristos break;
407ed0d50c3Schristos case e_immed:
408ed0d50c3Schristos c = 'i';
409ed0d50c3Schristos break;
410ed0d50c3Schristos case e_addr:
411ed0d50c3Schristos c = 'a';
412ed0d50c3Schristos break;
413ed0d50c3Schristos default:
414ed0d50c3Schristos c = 0; /* ignore; unknown field type */
415ed0d50c3Schristos }
416ed0d50c3Schristos if (c)
417ed0d50c3Schristos {
418ed0d50c3Schristos if (p != s)
419ed0d50c3Schristos *p++ = ',';
420ed0d50c3Schristos *p++ = c;
421ed0d50c3Schristos }
422ed0d50c3Schristos }
423ed0d50c3Schristos *p = 0;
424ed0d50c3Schristos return s;
425ed0d50c3Schristos }
426ed0d50c3Schristos #endif /* !STAND_ALONE */
427ed0d50c3Schristos
428ed0d50c3Schristos /* Get processor's register name from val */
429ed0d50c3Schristos
430ed0d50c3Schristos int
itbl_get_reg_val(char * name,unsigned long * pval)431ed0d50c3Schristos itbl_get_reg_val (char *name, unsigned long *pval)
432ed0d50c3Schristos {
433ed0d50c3Schristos e_type t;
434ed0d50c3Schristos e_processor p;
435ed0d50c3Schristos
436ed0d50c3Schristos for (p = e_p0; p < e_nprocs; p++)
437ed0d50c3Schristos {
438ed0d50c3Schristos for (t = e_regtype0; t < e_nregtypes; t++)
439ed0d50c3Schristos {
440ed0d50c3Schristos if (itbl_get_val (p, t, name, pval))
441ed0d50c3Schristos return 1;
442ed0d50c3Schristos }
443ed0d50c3Schristos }
444ed0d50c3Schristos return 0;
445ed0d50c3Schristos }
446ed0d50c3Schristos
447ed0d50c3Schristos char *
itbl_get_name(e_processor processor,e_type type,unsigned long val)448ed0d50c3Schristos itbl_get_name (e_processor processor, e_type type, unsigned long val)
449ed0d50c3Schristos {
450ed0d50c3Schristos struct itbl_entry *r;
451ed0d50c3Schristos /* type depends on instruction passed */
452ed0d50c3Schristos r = find_entry_byval (processor, type, val, 0);
453ed0d50c3Schristos if (r)
454ed0d50c3Schristos return r->name;
455ed0d50c3Schristos else
456ed0d50c3Schristos return 0; /* error; invalid operand */
457ed0d50c3Schristos }
458ed0d50c3Schristos
459ed0d50c3Schristos /* Get processor's register value from name */
460ed0d50c3Schristos
461ed0d50c3Schristos int
itbl_get_val(e_processor processor,e_type type,char * name,unsigned long * pval)462ed0d50c3Schristos itbl_get_val (e_processor processor, e_type type, char *name,
463ed0d50c3Schristos unsigned long *pval)
464ed0d50c3Schristos {
465ed0d50c3Schristos struct itbl_entry *r;
466ed0d50c3Schristos /* type depends on instruction passed */
467ed0d50c3Schristos r = find_entry_byname (processor, type, name);
468ed0d50c3Schristos if (r == NULL)
469ed0d50c3Schristos return 0;
470ed0d50c3Schristos *pval = r->value;
471ed0d50c3Schristos return 1;
472ed0d50c3Schristos }
473ed0d50c3Schristos
474ed0d50c3Schristos /* Assemble instruction "name" with operands "s".
475ed0d50c3Schristos * name - name of instruction
476ed0d50c3Schristos * s - operands
477ed0d50c3Schristos * returns - long word for assembled instruction */
478ed0d50c3Schristos
479ed0d50c3Schristos unsigned long
itbl_assemble(char * name,char * s)480ed0d50c3Schristos itbl_assemble (char *name, char *s)
481ed0d50c3Schristos {
482ed0d50c3Schristos unsigned long opcode;
483ed0d50c3Schristos struct itbl_entry *e = NULL;
484ed0d50c3Schristos struct itbl_field *f;
485ed0d50c3Schristos char *n;
486ed0d50c3Schristos int processor;
487ed0d50c3Schristos
488ed0d50c3Schristos if (!name || !*name)
489ed0d50c3Schristos return 0; /* error! must have an opcode name/expr */
490ed0d50c3Schristos
491ed0d50c3Schristos /* find entry in list of instructions for all processors */
492ed0d50c3Schristos for (processor = 0; processor < e_nprocs; processor++)
493ed0d50c3Schristos {
494ed0d50c3Schristos e = find_entry_byname (processor, e_insn, name);
495ed0d50c3Schristos if (e)
496ed0d50c3Schristos break;
497ed0d50c3Schristos }
498ed0d50c3Schristos if (!e)
499ed0d50c3Schristos return 0; /* opcode not in table; invalid instruction */
500ed0d50c3Schristos opcode = build_opcode (e);
501ed0d50c3Schristos
502ed0d50c3Schristos /* parse opcode's args (if any) */
503ed0d50c3Schristos for (f = e->fields; f; f = f->next) /* for each arg, ... */
504ed0d50c3Schristos {
505ed0d50c3Schristos struct itbl_entry *r;
506ed0d50c3Schristos unsigned long value;
507ed0d50c3Schristos if (!s || !*s)
508ed0d50c3Schristos return 0; /* error - not enough operands */
509ed0d50c3Schristos n = itbl_get_field (&s);
510ed0d50c3Schristos /* n should be in form $n or 0xhhh (are symbol names valid?? */
511ed0d50c3Schristos switch (f->type)
512ed0d50c3Schristos {
513ed0d50c3Schristos case e_dreg:
514ed0d50c3Schristos case e_creg:
515ed0d50c3Schristos case e_greg:
516ed0d50c3Schristos /* Accept either a string name
517ed0d50c3Schristos * or '$' followed by the register number */
518ed0d50c3Schristos if (*n == '$')
519ed0d50c3Schristos {
520ed0d50c3Schristos n++;
521ed0d50c3Schristos value = strtol (n, 0, 10);
522ed0d50c3Schristos /* FIXME! could have "0l"... then what?? */
523ed0d50c3Schristos if (value == 0 && *n != '0')
524ed0d50c3Schristos return 0; /* error; invalid operand */
525ed0d50c3Schristos }
526ed0d50c3Schristos else
527ed0d50c3Schristos {
528ed0d50c3Schristos r = find_entry_byname (e->processor, f->type, n);
529ed0d50c3Schristos if (r)
530ed0d50c3Schristos value = r->value;
531ed0d50c3Schristos else
532ed0d50c3Schristos return 0; /* error; invalid operand */
533ed0d50c3Schristos }
534ed0d50c3Schristos break;
535ed0d50c3Schristos case e_addr:
536ed0d50c3Schristos /* use assembler's symbol table to find symbol */
537ed0d50c3Schristos /* FIXME!! Do we need this?
538ed0d50c3Schristos if so, what about relocs??
539ed0d50c3Schristos my_getExpression (&imm_expr, s);
540ed0d50c3Schristos return 0; /-* error; invalid operand *-/
541ed0d50c3Schristos break;
542ed0d50c3Schristos */
543ed0d50c3Schristos /* If not a symbol, fallthru to IMMED */
544ed0d50c3Schristos case e_immed:
545ed0d50c3Schristos if (*n == '0' && *(n + 1) == 'x') /* hex begins 0x... */
546ed0d50c3Schristos {
547ed0d50c3Schristos n += 2;
548ed0d50c3Schristos value = strtol (n, 0, 16);
549ed0d50c3Schristos /* FIXME! could have "0xl"... then what?? */
550ed0d50c3Schristos }
551ed0d50c3Schristos else
552ed0d50c3Schristos {
553ed0d50c3Schristos value = strtol (n, 0, 10);
554ed0d50c3Schristos /* FIXME! could have "0l"... then what?? */
555ed0d50c3Schristos if (value == 0 && *n != '0')
556ed0d50c3Schristos return 0; /* error; invalid operand */
557ed0d50c3Schristos }
558ed0d50c3Schristos break;
559ed0d50c3Schristos default:
560ed0d50c3Schristos return 0; /* error; invalid field spec */
561ed0d50c3Schristos }
562ed0d50c3Schristos opcode |= apply_range (value, f->range);
563ed0d50c3Schristos }
564ed0d50c3Schristos if (s && *s)
565ed0d50c3Schristos return 0; /* error - too many operands */
566ed0d50c3Schristos return opcode; /* done! */
567ed0d50c3Schristos }
568ed0d50c3Schristos
569ed0d50c3Schristos /* Disassemble instruction "insn".
570ed0d50c3Schristos * insn - instruction
571ed0d50c3Schristos * s - buffer to hold disassembled instruction
572ed0d50c3Schristos * returns - 1 if succeeded; 0 if failed
573ed0d50c3Schristos */
574ed0d50c3Schristos
575ed0d50c3Schristos int
itbl_disassemble(char * s,unsigned long insn)576ed0d50c3Schristos itbl_disassemble (char *s, unsigned long insn)
577ed0d50c3Schristos {
578ed0d50c3Schristos e_processor processor;
579ed0d50c3Schristos struct itbl_entry *e;
580ed0d50c3Schristos struct itbl_field *f;
581ed0d50c3Schristos
582ed0d50c3Schristos if (!ITBL_IS_INSN (insn))
583ed0d50c3Schristos return 0; /* error */
584ed0d50c3Schristos processor = get_processor (ITBL_DECODE_PNUM (insn));
585ed0d50c3Schristos
586ed0d50c3Schristos /* find entry in list */
587ed0d50c3Schristos e = find_entry_byval (processor, e_insn, insn, 0);
588ed0d50c3Schristos if (!e)
589ed0d50c3Schristos return 0; /* opcode not in table; invalid instruction */
590ed0d50c3Schristos strcpy (s, e->name);
591ed0d50c3Schristos
592ed0d50c3Schristos /* Parse insn's args (if any). */
593ed0d50c3Schristos for (f = e->fields; f; f = f->next) /* for each arg, ... */
594ed0d50c3Schristos {
595ed0d50c3Schristos struct itbl_entry *r;
596ed0d50c3Schristos unsigned long value;
597ed0d50c3Schristos char s_value[20];
598ed0d50c3Schristos
599ed0d50c3Schristos if (f == e->fields) /* First operand is preceded by tab. */
600ed0d50c3Schristos strcat (s, "\t");
601ed0d50c3Schristos else /* ','s separate following operands. */
602ed0d50c3Schristos strcat (s, ",");
603ed0d50c3Schristos value = extract_range (insn, f->range);
604ed0d50c3Schristos /* n should be in form $n or 0xhhh (are symbol names valid?? */
605ed0d50c3Schristos switch (f->type)
606ed0d50c3Schristos {
607ed0d50c3Schristos case e_dreg:
608ed0d50c3Schristos case e_creg:
609ed0d50c3Schristos case e_greg:
610ed0d50c3Schristos /* Accept either a string name
611ed0d50c3Schristos or '$' followed by the register number. */
612ed0d50c3Schristos r = find_entry_byval (e->processor, f->type, value, &f->range);
613ed0d50c3Schristos if (r)
614ed0d50c3Schristos strcat (s, r->name);
615ed0d50c3Schristos else
616ed0d50c3Schristos {
617ed0d50c3Schristos sprintf (s_value, "$%lu", value);
618ed0d50c3Schristos strcat (s, s_value);
619ed0d50c3Schristos }
620ed0d50c3Schristos break;
621ed0d50c3Schristos case e_addr:
622ed0d50c3Schristos /* Use assembler's symbol table to find symbol. */
623ed0d50c3Schristos /* FIXME!! Do we need this? If so, what about relocs?? */
624ed0d50c3Schristos /* If not a symbol, fall through to IMMED. */
625ed0d50c3Schristos case e_immed:
626ed0d50c3Schristos sprintf (s_value, "0x%lx", value);
627ed0d50c3Schristos strcat (s, s_value);
628ed0d50c3Schristos break;
629ed0d50c3Schristos default:
630ed0d50c3Schristos return 0; /* error; invalid field spec */
631ed0d50c3Schristos }
632ed0d50c3Schristos }
633ed0d50c3Schristos return 1; /* Done! */
634ed0d50c3Schristos }
635ed0d50c3Schristos
636ed0d50c3Schristos /*======================================================================*/
637ed0d50c3Schristos /*
638ed0d50c3Schristos * Local functions for manipulating private structures containing
639ed0d50c3Schristos * the names and format for the new instructions and registers
640ed0d50c3Schristos * for each processor.
641ed0d50c3Schristos */
642ed0d50c3Schristos
643ed0d50c3Schristos /* Calculate instruction's opcode and function values from entry */
644ed0d50c3Schristos
645ed0d50c3Schristos static unsigned long
build_opcode(struct itbl_entry * e)646ed0d50c3Schristos build_opcode (struct itbl_entry *e)
647ed0d50c3Schristos {
648ed0d50c3Schristos unsigned long opcode;
649ed0d50c3Schristos
650ed0d50c3Schristos opcode = apply_range (e->value, e->range);
651ed0d50c3Schristos opcode |= ITBL_ENCODE_PNUM (e->processor);
652ed0d50c3Schristos return opcode;
653ed0d50c3Schristos }
654ed0d50c3Schristos
655ed0d50c3Schristos /* Calculate absolute value given the relative value and bit position range
656ed0d50c3Schristos * within the instruction.
657ed0d50c3Schristos * The range is inclusive where 0 is least significant bit.
658ed0d50c3Schristos * A range of { 24, 20 } will have a mask of
659ed0d50c3Schristos * bit 3 2 1
660ed0d50c3Schristos * pos: 1098 7654 3210 9876 5432 1098 7654 3210
661ed0d50c3Schristos * bin: 0000 0001 1111 0000 0000 0000 0000 0000
662ed0d50c3Schristos * hex: 0 1 f 0 0 0 0 0
663ed0d50c3Schristos * mask: 0x01f00000.
664ed0d50c3Schristos */
665ed0d50c3Schristos
666ed0d50c3Schristos static unsigned long
apply_range(unsigned long rval,struct itbl_range r)667ed0d50c3Schristos apply_range (unsigned long rval, struct itbl_range r)
668ed0d50c3Schristos {
669ed0d50c3Schristos unsigned long mask;
670ed0d50c3Schristos unsigned long aval;
671ed0d50c3Schristos int len = MAX_BITPOS - r.sbit;
672ed0d50c3Schristos
673ed0d50c3Schristos ASSERT (r.sbit >= r.ebit);
674ed0d50c3Schristos ASSERT (MAX_BITPOS >= r.sbit);
675ed0d50c3Schristos ASSERT (r.ebit >= 0);
676ed0d50c3Schristos
677ed0d50c3Schristos /* create mask by truncating 1s by shifting */
678ed0d50c3Schristos mask = 0xffffffff << len;
679ed0d50c3Schristos mask = mask >> len;
680ed0d50c3Schristos mask = mask >> r.ebit;
681ed0d50c3Schristos mask = mask << r.ebit;
682ed0d50c3Schristos
683ed0d50c3Schristos aval = (rval << r.ebit) & mask;
684ed0d50c3Schristos return aval;
685ed0d50c3Schristos }
686ed0d50c3Schristos
687ed0d50c3Schristos /* Calculate relative value given the absolute value and bit position range
688ed0d50c3Schristos * within the instruction. */
689ed0d50c3Schristos
690ed0d50c3Schristos static unsigned long
extract_range(unsigned long aval,struct itbl_range r)691ed0d50c3Schristos extract_range (unsigned long aval, struct itbl_range r)
692ed0d50c3Schristos {
693ed0d50c3Schristos unsigned long mask;
694ed0d50c3Schristos unsigned long rval;
695ed0d50c3Schristos int len = MAX_BITPOS - r.sbit;
696ed0d50c3Schristos
697ed0d50c3Schristos /* create mask by truncating 1s by shifting */
698ed0d50c3Schristos mask = 0xffffffff << len;
699ed0d50c3Schristos mask = mask >> len;
700ed0d50c3Schristos mask = mask >> r.ebit;
701ed0d50c3Schristos mask = mask << r.ebit;
702ed0d50c3Schristos
703ed0d50c3Schristos rval = (aval & mask) >> r.ebit;
704ed0d50c3Schristos return rval;
705ed0d50c3Schristos }
706ed0d50c3Schristos
707ed0d50c3Schristos /* Extract processor's assembly instruction field name from s;
708ed0d50c3Schristos * forms are "n args" "n,args" or "n" */
709ed0d50c3Schristos /* Return next argument from string pointer "s" and advance s.
710ed0d50c3Schristos * delimiters are " ,()" */
711ed0d50c3Schristos
712ed0d50c3Schristos char *
itbl_get_field(char ** S)713ed0d50c3Schristos itbl_get_field (char **S)
714ed0d50c3Schristos {
715ed0d50c3Schristos static char n[128];
716ed0d50c3Schristos char *s;
717ed0d50c3Schristos int len;
718ed0d50c3Schristos
719ed0d50c3Schristos s = *S;
720ed0d50c3Schristos if (!s || !*s)
721ed0d50c3Schristos return 0;
722ed0d50c3Schristos /* FIXME: This is a weird set of delimiters. */
723ed0d50c3Schristos len = strcspn (s, " \t,()");
724ed0d50c3Schristos ASSERT (128 > len + 1);
725ed0d50c3Schristos strncpy (n, s, len);
726ed0d50c3Schristos n[len] = 0;
727ed0d50c3Schristos if (s[len] == '\0')
728ed0d50c3Schristos s = 0; /* no more args */
729ed0d50c3Schristos else
730ed0d50c3Schristos s += len + 1; /* advance to next arg */
731ed0d50c3Schristos
732ed0d50c3Schristos *S = s;
733ed0d50c3Schristos return n;
734ed0d50c3Schristos }
735ed0d50c3Schristos
736ed0d50c3Schristos /* Search entries for a given processor and type
737ed0d50c3Schristos * to find one matching the name "n".
738ed0d50c3Schristos * Return a pointer to the entry */
739ed0d50c3Schristos
740ed0d50c3Schristos static struct itbl_entry *
find_entry_byname(e_processor processor,e_type type,char * n)741ed0d50c3Schristos find_entry_byname (e_processor processor,
742ed0d50c3Schristos e_type type, char *n)
743ed0d50c3Schristos {
744ed0d50c3Schristos struct itbl_entry *e, **es;
745ed0d50c3Schristos
746ed0d50c3Schristos es = get_entries (processor, type);
747ed0d50c3Schristos for (e = *es; e; e = e->next) /* for each entry, ... */
748ed0d50c3Schristos {
749ed0d50c3Schristos if (!strcmp (e->name, n))
750ed0d50c3Schristos return e;
751ed0d50c3Schristos }
752ed0d50c3Schristos return 0;
753ed0d50c3Schristos }
754ed0d50c3Schristos
755ed0d50c3Schristos /* Search entries for a given processor and type
756ed0d50c3Schristos * to find one matching the value "val" for the range "r".
757ed0d50c3Schristos * Return a pointer to the entry.
758ed0d50c3Schristos * This function is used for disassembling fields of an instruction.
759ed0d50c3Schristos */
760ed0d50c3Schristos
761ed0d50c3Schristos static struct itbl_entry *
find_entry_byval(e_processor processor,e_type type,unsigned long val,struct itbl_range * r)762ed0d50c3Schristos find_entry_byval (e_processor processor, e_type type,
763ed0d50c3Schristos unsigned long val, struct itbl_range *r)
764ed0d50c3Schristos {
765ed0d50c3Schristos struct itbl_entry *e, **es;
766ed0d50c3Schristos unsigned long eval;
767ed0d50c3Schristos
768ed0d50c3Schristos es = get_entries (processor, type);
769ed0d50c3Schristos for (e = *es; e; e = e->next) /* for each entry, ... */
770ed0d50c3Schristos {
771ed0d50c3Schristos if (processor != e->processor)
772ed0d50c3Schristos continue;
773ed0d50c3Schristos /* For insns, we might not know the range of the opcode,
774ed0d50c3Schristos * so a range of 0 will allow this routine to match against
775ed0d50c3Schristos * the range of the entry to be compared with.
776ed0d50c3Schristos * This could cause ambiguities.
777ed0d50c3Schristos * For operands, we get an extracted value and a range.
778ed0d50c3Schristos */
779ed0d50c3Schristos /* if range is 0, mask val against the range of the compared entry. */
780ed0d50c3Schristos if (r == 0) /* if no range passed, must be whole 32-bits
781ed0d50c3Schristos * so create 32-bit value from entry's range */
782ed0d50c3Schristos {
783ed0d50c3Schristos eval = apply_range (e->value, e->range);
784ed0d50c3Schristos val &= apply_range (0xffffffff, e->range);
785ed0d50c3Schristos }
786ed0d50c3Schristos else if ((r->sbit == e->range.sbit && r->ebit == e->range.ebit)
787ed0d50c3Schristos || (e->range.sbit == 0 && e->range.ebit == 0))
788ed0d50c3Schristos {
789ed0d50c3Schristos eval = apply_range (e->value, *r);
790ed0d50c3Schristos val = apply_range (val, *r);
791ed0d50c3Schristos }
792ed0d50c3Schristos else
793ed0d50c3Schristos continue;
794ed0d50c3Schristos if (val == eval)
795ed0d50c3Schristos return e;
796ed0d50c3Schristos }
797ed0d50c3Schristos return 0;
798ed0d50c3Schristos }
799ed0d50c3Schristos
800ed0d50c3Schristos /* Return a pointer to the list of entries for a given processor and type. */
801ed0d50c3Schristos
802ed0d50c3Schristos static struct itbl_entry **
get_entries(e_processor processor,e_type type)803ed0d50c3Schristos get_entries (e_processor processor, e_type type)
804ed0d50c3Schristos {
805ed0d50c3Schristos return &entries[processor][type];
806ed0d50c3Schristos }
807ed0d50c3Schristos
808ed0d50c3Schristos /* Return an integral value for the processor passed from yyparse. */
809ed0d50c3Schristos
810ed0d50c3Schristos static e_processor
get_processor(int yyproc)811ed0d50c3Schristos get_processor (int yyproc)
812ed0d50c3Schristos {
813ed0d50c3Schristos /* translate from yacc's processor to enum */
814ed0d50c3Schristos if (yyproc >= e_p0 && yyproc < e_nprocs)
815ed0d50c3Schristos return (e_processor) yyproc;
816ed0d50c3Schristos return e_invproc; /* error; invalid processor */
817ed0d50c3Schristos }
818ed0d50c3Schristos
819ed0d50c3Schristos /* Return an integral value for the entry type passed from yyparse. */
820ed0d50c3Schristos
821ed0d50c3Schristos static e_type
get_type(int yytype)822ed0d50c3Schristos get_type (int yytype)
823ed0d50c3Schristos {
824ed0d50c3Schristos switch (yytype)
825ed0d50c3Schristos {
826ed0d50c3Schristos /* translate from yacc's type to enum */
827ed0d50c3Schristos case INSN:
828ed0d50c3Schristos return e_insn;
829ed0d50c3Schristos case DREG:
830ed0d50c3Schristos return e_dreg;
831ed0d50c3Schristos case CREG:
832ed0d50c3Schristos return e_creg;
833ed0d50c3Schristos case GREG:
834ed0d50c3Schristos return e_greg;
835ed0d50c3Schristos case ADDR:
836ed0d50c3Schristos return e_addr;
837ed0d50c3Schristos case IMMED:
838ed0d50c3Schristos return e_immed;
839ed0d50c3Schristos default:
840ed0d50c3Schristos return e_invtype; /* error; invalid type */
841ed0d50c3Schristos }
842ed0d50c3Schristos }
843ed0d50c3Schristos
844ed0d50c3Schristos /* Allocate and initialize an entry */
845ed0d50c3Schristos
846ed0d50c3Schristos static struct itbl_entry *
alloc_entry(e_processor processor,e_type type,char * name,unsigned long value)847ed0d50c3Schristos alloc_entry (e_processor processor, e_type type,
848ed0d50c3Schristos char *name, unsigned long value)
849ed0d50c3Schristos {
850ed0d50c3Schristos struct itbl_entry *e, **es;
851ed0d50c3Schristos if (!name)
852ed0d50c3Schristos return 0;
853ed0d50c3Schristos e = XNEW (struct itbl_entry);
854ed0d50c3Schristos if (e)
855ed0d50c3Schristos {
856ed0d50c3Schristos memset (e, 0, sizeof (struct itbl_entry));
857ed0d50c3Schristos e->name = xstrdup (name);
858ed0d50c3Schristos e->processor = processor;
859ed0d50c3Schristos e->type = type;
860ed0d50c3Schristos e->value = value;
861ed0d50c3Schristos es = get_entries (e->processor, e->type);
862ed0d50c3Schristos e->next = *es;
863ed0d50c3Schristos *es = e;
864ed0d50c3Schristos }
865ed0d50c3Schristos return e;
866ed0d50c3Schristos }
867ed0d50c3Schristos
868ed0d50c3Schristos /* Allocate and initialize an entry's field */
869ed0d50c3Schristos
870ed0d50c3Schristos static struct itbl_field *
alloc_field(e_type type,int sbit,int ebit,unsigned long flags)871ed0d50c3Schristos alloc_field (e_type type, int sbit, int ebit,
872ed0d50c3Schristos unsigned long flags)
873ed0d50c3Schristos {
874ed0d50c3Schristos struct itbl_field *f;
875ed0d50c3Schristos f = XNEW (struct itbl_field);
876ed0d50c3Schristos if (f)
877ed0d50c3Schristos {
878ed0d50c3Schristos memset (f, 0, sizeof (struct itbl_field));
879ed0d50c3Schristos f->type = type;
880ed0d50c3Schristos f->range.sbit = sbit;
881ed0d50c3Schristos f->range.ebit = ebit;
882ed0d50c3Schristos f->flags = flags;
883ed0d50c3Schristos }
884ed0d50c3Schristos return f;
885ed0d50c3Schristos }
886