From 5cfc98c9c3ae698c7e738e9cadaf210f1e5e14fa Mon Sep 17 00:00:00 2001 From: Nelson Chu Date: Wed, 22 Aug 2018 09:48:17 +0800 Subject: [PATCH 02/13] NDS32: Refactor the assembler and disassembler. To improve the expandability and maintainability, we may need many opcode, keyword, and operand hash tables for different usage in the future. This patch modify the corresponding implementation in the assembler and disassembler. opcodes/ * nds32-asm.c (config.h, stdlib.h, string.h): New includes. (LEX_SET_FIELD, LEX_GET_FIELD): Update defines. (nds32_asm_init, build_operand_hash_table, build_keyword_hash_table, build_opcode_hash_table): New functions. (nds32_keyword_table, nds32_keyword_count_table, nds32_field_table, nds32_opcode_table): New. (hw_ktabs): Declare it to a pointer rather than an array. (build_hash_table): Removed. * nds32-asm.h (enum): Add SYN_INPUT, SYN_OUTPUT, SYN_LOPT, SYN_ROPT and upadte HW_GPR and HW_INT. * nds32-dis.c (keywords): Remove const. (match_field): New function. (nds32_parse_opcode): Updated. --- opcodes/nds32-asm.c | 228 +++++++++++++++++++++++++++++++------------- opcodes/nds32-asm.h | 27 +++--- opcodes/nds32-dis.c | 45 ++++++--- 3 files changed, 210 insertions(+), 90 deletions(-) diff --git a/opcodes/nds32-asm.c b/opcodes/nds32-asm.c index f8d075c845..e15e308307 100644 --- a/opcodes/nds32-asm.c +++ b/opcodes/nds32-asm.c @@ -31,6 +31,10 @@ #include "bfd.h" #include "opintl.h" +#include +#include +#include + #include "opcode/nds32.h" #include "nds32-asm.h" @@ -42,8 +46,8 @@ #define MAX_KEYWORD_LEN 32 /* This LEX is a plain char or operand. */ #define IS_LEX_CHAR(c) (((c) >> 7) == 0) -#define LEX_SET_FIELD(c) ((c) | SYN_FIELD) -#define LEX_GET_FIELD(c) operand_fields[((c) & 0xff)] +#define LEX_SET_FIELD(k,c) ((c) | (((k) + 1) << 8)) +#define LEX_GET_FIELD(k,c) (nds32_field_table[k])[((c) & 0xff)] /* Get the char in this lexical element. */ #define LEX_CHAR(c) ((c) & 0xff) @@ -1362,13 +1366,19 @@ const keyword_t *keywords[_HW_LAST] = keyword_im5_i, keyword_im5_m, keyword_accumulator, keyword_aridx, keyword_aridx2, keyword_aridxi }; + +const keyword_t **nds32_keyword_table[NDS32_CORE_COUNT]; +static unsigned int nds32_keyword_count_table[NDS32_CORE_COUNT]; +const field_t *nds32_field_table[NDS32_CORE_COUNT]; +opcode_t *nds32_opcode_table[NDS32_CORE_COUNT]; + /* Hash table for syntax lex. */ static htab_t field_htab; /* Hash table for opcodes. */ static htab_t opcode_htab; /* Hash table for hardware resources. */ -static htab_t hw_ktabs[_HW_LAST]; +static htab_t *hw_ktabs; static hashval_t htab_hash_hash (const void *p) @@ -1387,43 +1397,88 @@ htab_hash_eq (const void *p, const void *q) return strcmp (name, h->name) == 0; } -/* Build a hash table for array BASE. Each element is in size of SIZE, - and it's first element is a pointer to the key of string. - It stops inserting elements until reach an NULL key. */ -static htab_t -build_hash_table (const void *base, size_t size) +static void +build_operand_hash_table (void) { - htab_t htab; - hashval_t hash; - const char *p; + unsigned k; - htab = htab_create_alloc (128, htab_hash_hash, htab_hash_eq, - NULL, xcalloc, free); + field_htab = htab_create_alloc (128, htab_hash_hash, htab_hash_eq, + NULL, xcalloc, free); - p = base; - while (1) + for (k = 0; k < NDS32_CORE_COUNT; k++) { - struct nds32_hash_entry **slot; - struct nds32_hash_entry *h; + const field_t *fld; - h = (struct nds32_hash_entry *) p; + fld = nds32_field_table[k]; + if (fld == NULL) + continue; - if (h->name == NULL) - break; + /* Add op-codes. */ + while (fld->name != NULL) + { + hashval_t hash; + const field_t **slot; + + hash = htab_hash_string (fld->name); + slot = (const field_t **) + htab_find_slot_with_hash (field_htab, fld->name, hash, INSERT); - hash = htab_hash_string (h->name); - slot = (struct nds32_hash_entry **) - htab_find_slot_with_hash (htab, h->name, hash, INSERT); + assert (slot != NULL && *slot == NULL); + *slot = fld++; + } + } +} - assert (slot != NULL && *slot == NULL); +static void +build_keyword_hash_table (void) +{ + unsigned int i, j, k, n; - *slot = h; + /* Count total keyword tables. */ + for (n = 0, i = 0; i < NDS32_CORE_COUNT; i++) + { + n += nds32_keyword_count_table[i]; + } - p = p + size; + /* Allocate space. */ + hw_ktabs = (htab_t *) malloc (n * sizeof (struct htab)); + for (i = 0; i < n; i++) + { + hw_ktabs[i] = htab_create_alloc (128, htab_hash_hash, htab_hash_eq, + NULL, xcalloc, free); } - return htab; + for (n = 0, k = 0; k < NDS32_CORE_COUNT; k++, n += j) + { + const keyword_t **kwd; + + if ((j = nds32_keyword_count_table[k]) == 0) + continue; + + /* Add keywords. */ + kwd = nds32_keyword_table[k]; + for (i = 0; i < j; i++) + { + htab_t htab; + const keyword_t *kw; + + kw = kwd[i]; + htab = hw_ktabs[n + i]; + while (kw->name != NULL) + { + hashval_t hash; + const keyword_t **slot; + + hash = htab_hash_string (kw->name); + slot = (const keyword_t **) + htab_find_slot_with_hash (htab, kw->name, hash, INSERT); + + assert (slot != NULL && *slot == NULL); + *slot = kw++; + } + } + } } /* Build the syntax for a given opcode OPC. It parses the string @@ -1448,12 +1503,13 @@ build_opcode_syntax (struct nds32_opcode *opc) return; opc->syntax = xmalloc (MAX_LEX_NUM * sizeof (lex_t)); + memset (opc->syntax, 0, MAX_LEX_NUM * sizeof (lex_t)); str = opc->instruction; plex = opc->syntax; while (*str) { - int fidx; + int fidx, i, k; switch (*str) { @@ -1491,7 +1547,6 @@ build_opcode_syntax (struct nds32_opcode *opc) hash = htab_hash_string (odstr); fd = (field_t *) htab_find_with_hash (field_htab, odstr, hash); - fidx = fd - operand_fields; if (fd == NULL) { @@ -1499,8 +1554,22 @@ build_opcode_syntax (struct nds32_opcode *opc) opcodes_error_handler (_("internal error: unknown operand, %s"), str); abort (); } + + /* We are not sure how these tables are organized. */ + /* Thus, the minimal index should be the right one. */ + for (fidx = 256, k = 0, i = 0; i < NDS32_CORE_COUNT; i++) + { + int tmp; + + tmp = fd - nds32_field_table[i]; + if (tmp >= 0 && tmp < fidx) + { + fidx = tmp; + k = i; + } + } assert (fidx >= 0 && fidx < (int) ARRAY_SIZE (operand_fields)); - *plex |= LEX_SET_FIELD (fidx); + *plex |= LEX_SET_FIELD (k, fidx); str += len; plex++; @@ -1511,44 +1580,37 @@ build_opcode_syntax (struct nds32_opcode *opc) return; } -/* Initialize the assembler. It must be called before assembling. */ - -void -nds32_asm_init (nds32_asm_desc_t *pdesc, int flags) +static void +build_opcode_hash_table (void) { - int i; - hashval_t hash; + unsigned k; - pdesc->flags = flags; - pdesc->mach = flags & NASM_OPEN_ARCH_MASK; - - /* Build keyword tables. */ - field_htab = build_hash_table (operand_fields, - sizeof (operand_fields[0])); - - for (i = 0; i < _HW_LAST; i++) - hw_ktabs[i] = build_hash_table (keywords[i], sizeof (keyword_t)); - - /* Build opcode table. */ - opcode_htab = htab_create_alloc (128, htab_hash_hash, htab_hash_eq, + opcode_htab = htab_create_alloc (512, htab_hash_hash, htab_hash_eq, NULL, xcalloc, free); - for (i = 0; i < (int) ARRAY_SIZE (nds32_opcodes); i++) + for (k = 0; k < NDS32_CORE_COUNT; k++) { - struct nds32_opcode **slot; - struct nds32_opcode *opc; + opcode_t *opc; + + opc = nds32_opcode_table[k]; + if (opc == NULL) + continue; - opc = &nds32_opcodes[i]; - if ((opc->opcode != NULL) && (opc->instruction != NULL)) + /* Add op-codes. */ + while ((opc->opcode != NULL) && (opc->instruction != NULL)) { + hashval_t hash; + opcode_t **slot; + hash = htab_hash_string (opc->opcode); - slot = (struct nds32_opcode **) - htab_find_slot_with_hash (opcode_htab, opc->opcode, hash, INSERT); + slot = (opcode_t **) + htab_find_slot_with_hash (opcode_htab, opc->opcode, hash, + INSERT); #define NDS32_PREINIT_SYNTAX #if defined (NDS32_PREINIT_SYNTAX) - /* Initial SYNTAX when build opcode table, so bug in syntax can be - found when initialized rather than used. */ + /* Initial SYNTAX when build opcode table, so bug in syntax + can be found when initialized rather than used. */ build_opcode_syntax (opc); #endif @@ -1559,16 +1621,44 @@ nds32_asm_init (nds32_asm_desc_t *pdesc, int flags) } else { + opcode_t *ptr; + /* Already exists. Append to the list. */ - opc = *slot; - while (opc->next) - opc = opc->next; - opc->next = &nds32_opcodes[i]; + ptr = *slot; + while (ptr->next) + ptr = ptr->next; + ptr->next = opc; + opc->next = NULL; } + opc++; } } } +/* Initialize the assembler. It must be called before assembling. */ + +void +nds32_asm_init (nds32_asm_desc_t *pdesc, int flags) +{ + pdesc->flags = flags; + pdesc->mach = flags & NASM_OPEN_ARCH_MASK; + + /* Setup main core. */ + nds32_keyword_table[NDS32_MAIN_CORE] = &keywords[0]; + nds32_keyword_count_table[NDS32_MAIN_CORE] = _HW_LAST; + nds32_opcode_table[NDS32_MAIN_CORE] = &nds32_opcodes[0]; + nds32_field_table[NDS32_MAIN_CORE] = &operand_fields[0]; + + /* Build operand hash table. */ + build_operand_hash_table (); + + /* Build keyword hash tables. */ + build_keyword_hash_table (); + + /* Build op-code hash table. */ + build_opcode_hash_table (); +} + /* Parse the input and store operand keyword string in ODSTR. This function is only used for parsing keywords, HW_INT/HW_UINT are parsed parse_operand callback handler. */ @@ -1944,9 +2034,9 @@ parse_operand (nds32_asm_desc_t *pdesc, nds32_asm_insn_t *pinsn, char odstr[MAX_KEYWORD_LEN]; char *end; hashval_t hash; - const field_t *fld = &LEX_GET_FIELD (syn); + const field_t *fld = &LEX_GET_FIELD (((syn >> 8) & 0xff) - 1, syn); keyword_t *k; - int64_t value; + int64_t value = 0; /* 0x100000000; Big enough to overflow. */ int r; uint64_t modifier = 0; @@ -1963,15 +2053,23 @@ parse_operand (nds32_asm_desc_t *pdesc, nds32_asm_insn_t *pinsn, goto done; } - if (fld->hw_res < _HW_LAST) + /* Check valid keyword group. */ + if (fld->hw_res < HW_INT) { + int n = 0, i; + + /* Calculate index of keyword hash table. */ + for (i = 0; i < (fld->hw_res >> 8); i++) + n += nds32_keyword_count_table[i]; + /* Parse the operand in assembly code. */ if (*end == '$') end++; end = parse_to_delimiter (end, odstr); hash = htab_hash_string (odstr); - k = htab_find_with_hash (hw_ktabs[fld->hw_res], odstr, hash); + k = htab_find_with_hash (hw_ktabs[n + (fld->hw_res & 0xff)], odstr, + hash); if (k == NULL) { diff --git a/opcodes/nds32-asm.h b/opcodes/nds32-asm.h index c67e590c64..54775d66bb 100644 --- a/opcodes/nds32-asm.h +++ b/opcodes/nds32-asm.h @@ -87,19 +87,22 @@ enum NASM_ATTR_RDREG = 0x000100 }; +/* We only support one core for now. */ +#define NDS32_CORE_COUNT 1 +#define NDS32_MAIN_CORE 0 + enum { - /* This is a field (operand) of just a separator char. */ - SYN_FIELD = 0x100, - /* This operand is used for input or output. (define or use) */ - SYN_INPUT = 0x1000, - SYN_OUTPUT = 0x2000, - SYN_LOPT = 0x4000, - SYN_ROPT = 0x8000, - - /* Hardware resources. */ - HW_GPR = 0, + SYN_INPUT = 0x10000, + SYN_OUTPUT = 0x20000, + SYN_LOPT = 0x40000, + SYN_ROPT = 0x80000, + + /* Hardware resources: + Current set up allows up to 256 resources for each class + defined above. */ + HW_GPR = NDS32_MAIN_CORE << 8, HW_USR, HW_DXR, HW_SR, @@ -129,9 +132,7 @@ enum HW_AEXT_ARIDX2, HW_AEXT_ARIDXI, _HW_LAST, - /* TODO: Maybe we should add a new type to distinguish address and - const int. Only the former allows symbols and relocations. */ - HW_INT, + HW_INT = 0x1000, HW_UINT }; diff --git a/opcodes/nds32-dis.c b/opcodes/nds32-dis.c index c1ccc3e54b..1207fd37c7 100644 --- a/opcodes/nds32-dis.c +++ b/opcodes/nds32-dis.c @@ -40,9 +40,12 @@ #define NDS32_PARSE_INSN16 0x01 #define NDS32_PARSE_INSN32 0x02 +extern const field_t *nds32_field_table[NDS32_CORE_COUNT]; +extern opcode_t *nds32_opcode_table[NDS32_CORE_COUNT]; +extern keyword_t **nds32_keyword_table[NDS32_CORE_COUNT]; extern struct nds32_opcode nds32_opcodes[]; extern const field_t operand_fields[]; -extern const keyword_t *keywords[]; +extern keyword_t *keywords[]; extern const keyword_t keyword_gpr[]; static void print_insn16 (bfd_vma pc, disassemble_info *info, uint32_t insn, uint32_t parse_mode); @@ -167,6 +170,30 @@ nds32_parse_audio_ext (const field_t *pfd, func (stream, "$%s", psys_reg->name); } +/* Match instruction opcode with keyword table. */ + +static field_t * +match_field (char *name) +{ + field_t *pfd; + int k; + + for (k = 0; k < NDS32_CORE_COUNT; k++) + { + pfd = (field_t *) nds32_field_table[k]; + while (1) + { + if (pfd->name == NULL) + break; + if (strcmp (name, pfd->name) == 0) + return pfd; + pfd++; + } + } + + return NULL; +} + /* Dump instruction. If the opcode is unknown, return FALSE. */ static void @@ -237,15 +264,8 @@ nds32_parse_opcode (struct nds32_opcode *opc, bfd_vma pc ATTRIBUTE_UNUSED, } *pstr_tmp = 0; - pfd = (const field_t *) &operand_fields[0]; - while (1) - { - if (pfd->name == NULL) - return; - else if (strcmp (&tmp_string[0], pfd->name) == 0) - break; - pfd++; - } + if ((pfd = match_field (&tmp_string[0])) == NULL) + return; /* For insn-16. */ if (parse_mode & NDS32_PARSE_INSN16) @@ -330,12 +350,13 @@ nds32_parse_opcode (struct nds32_opcode *opc, bfd_vma pc ATTRIBUTE_UNUSED, nds32_parse_audio_ext (pfd, info, insn); } /* for insn-32. */ - else if (pfd->hw_res < _HW_LAST) + else if (pfd->hw_res < HW_INT) { int_value = __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; - psys_reg = (keyword_t*) keywords[pfd->hw_res]; + psys_reg = *(nds32_keyword_table[pfd->hw_res >> 8] + + (pfd->hw_res & 0xff)); psys_reg = nds32_find_reg_keyword (psys_reg, int_value); /* For HW_SR, dump the index when it can't -- 2.19.0