itbl-ops.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 903 行 · 第 1/2 页
C
903 行
/* itbl-ops.c Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GAS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//*======================================================================*//* * Herein lies the support for dynamic specification of processor * instructions and registers. Mnemonics, values, and formats for each * instruction and register are specified in an ascii file consisting of * table entries. The grammar for the table is defined in the document * "Processor instruction table specification". * * Instructions use the gnu assembler syntax, with the addition of * allowing mnemonics for register. * Eg. "func $2,reg3,0x100,symbol ; comment" * func - opcode name * $n - register n * reg3 - mnemonic for processor's register defined in table * 0xddd..d - immediate value * symbol - address of label or external symbol * * First, itbl_parse reads in the table of register and instruction * names and formats, and builds a list of entries for each * processor/type combination. lex and yacc are used to parse * the entries in the table and call functions defined here to * add each entry to our list. * * Then, when assembling or disassembling, these functions are called to * 1) get information on a processor's registers and * 2) assemble/disassemble an instruction. * To assemble(disassemble) an instruction, the function * itbl_assemble(itbl_disassemble) is called to search the list of * instruction entries, and if a match is found, uses the format * described in the instruction entry structure to complete the action. * * Eg. Suppose we have a Mips coprocessor "cop3" with data register "d2" * and we want to define function "pig" which takes two operands. * * Given the table entries: * "p3 insn pig 0x1:24-21 dreg:20-16 immed:15-0" * "p3 dreg d2 0x2" * and that the instruction encoding for coprocessor pz has encoding: * #define MIPS_ENCODE_COP_NUM(z) ((0x21|(z<<1))<<25) * #define ITBL_ENCODE_PNUM(pnum) MIPS_ENCODE_COP_NUM(pnum) * * a structure to describe the instruction might look something like: * struct itbl_entry = { * e_processor processor = e_p3 * e_type type = e_insn * char *name = "pig" * uint value = 0x1 * uint flags = 0 * struct itbl_range range = 24-21 * struct itbl_field *field = { * e_type type = e_dreg * struct itbl_range range = 20-16 * struct itbl_field *next = { * e_type type = e_immed * struct itbl_range range = 15-0 * struct itbl_field *next = 0 * }; * }; * struct itbl_entry *next = 0 * }; * * And the assembler instructions: * "pig d2,0x100" * "pig $2,0x100" * * would both assemble to the hex value: * "0x4e220100" * */#include <stdio.h>#include <stdlib.h>#include <string.h>#include "itbl-ops.h"#include "itbl-parse.h"/* #define DEBUG */#ifdef DEBUG#include <assert.h>#define ASSERT(x) assert(x)#define DBG(x) printf x#else#define ASSERT(x)#define DBG(x)#endif#ifndef min#define min(a,b) (a<b?a:b)#endifint itbl_have_entries = 0;/*======================================================================*//* structures for keeping itbl format entries */struct itbl_range { int sbit; /* mask starting bit position */ int ebit; /* mask ending bit position */};struct itbl_field { e_type type; /* dreg/creg/greg/immed/symb */ struct itbl_range range; /* field's bitfield range within instruction */ unsigned long flags; /* field flags */ struct itbl_field *next; /* next field in list */};/* These structures define the instructions and registers for a processor. * If the type is an instruction, the structure defines the format of an * instruction where the fields are the list of operands. * The flags field below uses the same values as those defined in the * gnu assembler and are machine specific. */struct itbl_entry { e_processor processor; /* processor number */ e_type type; /* dreg/creg/greg/insn */ char *name; /* mnemionic name for insn/register */ unsigned long value; /* opcode/instruction mask/register number */ unsigned long flags; /* effects of the instruction */ struct itbl_range range; /* bit range within instruction for value */ struct itbl_field *fields; /* list of operand definitions (if any) */ struct itbl_entry *next; /* next entry */};/* local data and structures */static int itbl_num_opcodes = 0;/* Array of entries for each processor and entry type */static struct itbl_entry *entries[e_nprocs][e_ntypes] = { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}};/* local prototypes */static unsigned long build_opcode PARAMS ((struct itbl_entry *e));static e_type get_type PARAMS ((int yytype));static e_processor get_processor PARAMS ((int yyproc));static struct itbl_entry **get_entries PARAMS ((e_processor processor, e_type type));static struct itbl_entry *find_entry_byname PARAMS ((e_processor processor, e_type type, char *name));static struct itbl_entry *find_entry_byval PARAMS ((e_processor processor, e_type type, unsigned long val, struct itbl_range *r));static struct itbl_entry *alloc_entry PARAMS ((e_processor processor, e_type type, char *name, unsigned long value));static unsigned long apply_range PARAMS ((unsigned long value, struct itbl_range r));static unsigned long extract_range PARAMS ((unsigned long value, struct itbl_range r));static struct itbl_field *alloc_field PARAMS ((e_type type, int sbit, int ebit, unsigned long flags));/*======================================================================*//* Interfaces to the parser *//* Open the table and use lex and yacc to parse the entries. * Return 1 for failure; 0 for success. */intitbl_parse (char *insntbl){ extern FILE *yyin; extern int yyparse (void); yyin = fopen (insntbl, "r"); if (yyin == 0) { printf ("Can't open processor instruction specification file \"%s\"\n", insntbl); return 1; } else { while (yyparse ()); } fclose (yyin); itbl_have_entries = 1; return 0;}/* Add a register entry */struct itbl_entry *itbl_add_reg (int yyprocessor, int yytype, char *regname, int regnum){#if 0#include "as.h"#include "symbols.h" /* Since register names don't have a prefix, we put them in the symbol table so they can't be used as symbols. This also simplifies argument parsing as we can let gas parse registers for us. The recorded register number is regnum. */ /* Use symbol_create here instead of symbol_new so we don't try to output registers into the object file's symbol table. */ symbol_table_insert (symbol_create (regname, reg_section, regnum, &zero_address_frag));#endif return alloc_entry (get_processor (yyprocessor), get_type (yytype), regname, (unsigned long) regnum);}/* Add an instruction entry */struct itbl_entry *itbl_add_insn (int yyprocessor, char *name, unsigned long value, int sbit, int ebit, unsigned long flags){ struct itbl_entry *e; e = alloc_entry (get_processor (yyprocessor), e_insn, name, value); if (e) { e->range.sbit = sbit; e->range.ebit = ebit; e->flags = flags; itbl_num_opcodes++; } return e;}/* Add an operand to an instruction entry */struct itbl_field *itbl_add_operand (struct itbl_entry *e, int yytype, int sbit, int ebit, unsigned long flags){ struct itbl_field *f, **last_f; if (!e) return 0; /* Add to end of fields' list. */ f = alloc_field (get_type (yytype), sbit, ebit, flags); if (f) { last_f = &e->fields; while (*last_f) last_f = &(*last_f)->next; *last_f = f; f->next = 0; } return f;}/*======================================================================*//* Interfaces for assembler and disassembler */#ifndef STAND_ALONE#include "as.h"#include "symbols.h"static void append_insns_as_macros (void);/* Initialize for gas. */voiditbl_init (void){ struct itbl_entry *e, **es; e_processor procn; e_type type; if (!itbl_have_entries) return; /* Since register names don't have a prefix, put them in the symbol table so they can't be used as symbols. This simplifies argument parsing as we can let gas parse registers for us. */ /* Use symbol_create instead of symbol_new so we don't try to output registers into the object file's symbol table. */ for (type = e_regtype0; type < e_nregtypes; type++) for (procn = e_p0; procn < e_nprocs; procn++) { es = get_entries (procn, type); for (e = *es; e; e = e->next) { symbol_table_insert (symbol_create (e->name, reg_section, e->value, &zero_address_frag)); } } append_insns_as_macros ();}/* Append insns to opcodes table and increase number of opcodes * Structure of opcodes table: * struct itbl_opcode * { * const char *name; * const char *args; - string describing the arguments. * unsigned long match; - opcode, or ISA level if pinfo=INSN_MACRO * unsigned long mask; - opcode mask, or macro id if pinfo=INSN_MACRO * unsigned long pinfo; - insn flags, or INSN_MACRO * }; * examples: * {"li", "t,i", 0x34000000, 0xffe00000, WR_t }, * {"li", "t,I", 0, (int) M_LI, INSN_MACRO }, */static char *form_args (struct itbl_entry *e);static voidappend_insns_as_macros (void){ struct ITBL_OPCODE_STRUCT *new_opcodes, *o; struct itbl_entry *e, **es; int n, id, size, new_size, new_num_opcodes; if (!itbl_have_entries) return; if (!itbl_num_opcodes) /* no new instructions to add! */ { return; } DBG (("previous num_opcodes=%d\n", ITBL_NUM_OPCODES)); new_num_opcodes = ITBL_NUM_OPCODES + itbl_num_opcodes; ASSERT (new_num_opcodes >= itbl_num_opcodes); size = sizeof (struct ITBL_OPCODE_STRUCT) * ITBL_NUM_OPCODES; ASSERT (size >= 0); DBG (("I get=%d\n", size / sizeof (ITBL_OPCODES[0]))); new_size = sizeof (struct ITBL_OPCODE_STRUCT) * new_num_opcodes; ASSERT (new_size > size); /* FIXME since ITBL_OPCODES culd be a static table, we can't realloc or delete the old memory. */ new_opcodes = (struct ITBL_OPCODE_STRUCT *) malloc (new_size); if (!new_opcodes) { printf (_("Unable to allocate memory for new instructions\n")); return; } if (size) /* copy prexisting opcodes table */ memcpy (new_opcodes, ITBL_OPCODES, size); /* FIXME! some NUMOPCODES are calculated expressions. These need to be changed before itbls can be supported. */ id = ITBL_NUM_MACROS; /* begin the next macro id after the last */ o = &new_opcodes[ITBL_NUM_OPCODES]; /* append macro to opcodes list */ for (n = e_p0; n < e_nprocs; n++) { es = get_entries (n, e_insn); for (e = *es; e; e = e->next) { /* name, args, mask, match, pinfo * {"li", "t,i", 0x34000000, 0xffe00000, WR_t }, * {"li", "t,I", 0, (int) M_LI, INSN_MACRO }, * Construct args from itbl_fields. */ o->name = e->name; o->args = strdup (form_args (e)); o->mask = apply_range (e->value, e->range); /* FIXME how to catch durring assembly? */ /* mask to identify this insn */ o->match = apply_range (e->value, e->range); o->pinfo = 0;#ifdef USE_MACROS o->mask = id++; /* FIXME how to catch durring assembly? */ o->match = 0; /* for macros, the insn_isa number */ o->pinfo = INSN_MACRO;#endif /* Don't add instructions which caused an error */ if (o->args) o++; else new_num_opcodes--; } } ITBL_OPCODES = new_opcodes; ITBL_NUM_OPCODES = new_num_opcodes; /* FIXME At this point, we can free the entries, as they should have been added to the assembler's tables. Don't free name though, since name is being used by the new opcodes table. Eventually, we should also free the new opcodes table itself on exit. */}static char *form_args (struct itbl_entry *e){ static char s[31]; char c = 0, *p = s; struct itbl_field *f; ASSERT (e); for (f = e->fields; f; f = f->next) { switch (f->type) { case e_dreg: c = 'd'; break; case e_creg: c = 't'; break; case e_greg: c = 's'; break; case e_immed: c = 'i'; break; case e_addr: c = 'a'; break; default: c = 0; /* ignore; unknown field type */ } if (c) { if (p != s) *p++ = ','; *p++ = c; } } *p = 0; return s;}#endif /* !STAND_ALONE *//* Get processor's register name from val */intitbl_get_reg_val (char *name, unsigned long *pval){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?