175fd0b74Schristos /* ARC target-dependent stuff. Extension structure access functions
2*e992f068Schristos Copyright (C) 1995-2022 Free Software Foundation, Inc.
375fd0b74Schristos
475fd0b74Schristos This file is part of libopcodes.
575fd0b74Schristos
675fd0b74Schristos This library is free software; you can redistribute it and/or modify
775fd0b74Schristos it under the terms of the GNU General Public License as published by
875fd0b74Schristos the Free Software Foundation; either version 3, or (at your option)
975fd0b74Schristos any later version.
1075fd0b74Schristos
1175fd0b74Schristos It is distributed in the hope that it will be useful, but WITHOUT
1275fd0b74Schristos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1375fd0b74Schristos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
1475fd0b74Schristos License for more details.
1575fd0b74Schristos
1675fd0b74Schristos You should have received a copy of the GNU General Public License
1775fd0b74Schristos along with this program; if not, write to the Free Software
1875fd0b74Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
1975fd0b74Schristos MA 02110-1301, USA. */
2075fd0b74Schristos
2175fd0b74Schristos #include "sysdep.h"
2275fd0b74Schristos #include <stdlib.h>
2375fd0b74Schristos #include <stdio.h>
2475fd0b74Schristos
2575fd0b74Schristos #include "bfd.h"
2675fd0b74Schristos #include "arc-ext.h"
2775fd0b74Schristos #include "elf/arc.h"
2875fd0b74Schristos #include "libiberty.h"
2975fd0b74Schristos
3075fd0b74Schristos /* This module provides support for extensions to the ARC processor
3175fd0b74Schristos architecture. */
3275fd0b74Schristos
3375fd0b74Schristos
3475fd0b74Schristos /* Local constants. */
3575fd0b74Schristos
3675fd0b74Schristos #define FIRST_EXTENSION_CORE_REGISTER 32
3775fd0b74Schristos #define LAST_EXTENSION_CORE_REGISTER 59
3875fd0b74Schristos #define FIRST_EXTENSION_CONDITION_CODE 0x10
3975fd0b74Schristos #define LAST_EXTENSION_CONDITION_CODE 0x1f
4075fd0b74Schristos
4175fd0b74Schristos #define NUM_EXT_CORE \
4275fd0b74Schristos (LAST_EXTENSION_CORE_REGISTER - FIRST_EXTENSION_CORE_REGISTER + 1)
4375fd0b74Schristos #define NUM_EXT_COND \
4475fd0b74Schristos (LAST_EXTENSION_CONDITION_CODE - FIRST_EXTENSION_CONDITION_CODE + 1)
4575fd0b74Schristos #define INST_HASH_BITS 6
4675fd0b74Schristos #define INST_HASH_SIZE (1 << INST_HASH_BITS)
4775fd0b74Schristos #define INST_HASH_MASK (INST_HASH_SIZE - 1)
4875fd0b74Schristos
4975fd0b74Schristos
5075fd0b74Schristos /* Local types. */
5175fd0b74Schristos
5275fd0b74Schristos /* These types define the information stored in the table. */
5375fd0b74Schristos
5475fd0b74Schristos struct ExtAuxRegister
5575fd0b74Schristos {
56012573ebSchristos unsigned address;
5775fd0b74Schristos char * name;
5875fd0b74Schristos struct ExtAuxRegister * next;
5975fd0b74Schristos };
6075fd0b74Schristos
6175fd0b74Schristos struct ExtCoreRegister
6275fd0b74Schristos {
6375fd0b74Schristos short number;
6475fd0b74Schristos enum ExtReadWrite rw;
6575fd0b74Schristos char * name;
6675fd0b74Schristos };
6775fd0b74Schristos
6875fd0b74Schristos struct arcExtMap
6975fd0b74Schristos {
7075fd0b74Schristos struct ExtAuxRegister* auxRegisters;
7175fd0b74Schristos struct ExtInstruction* instructions[INST_HASH_SIZE];
7275fd0b74Schristos struct ExtCoreRegister coreRegisters[NUM_EXT_CORE];
7375fd0b74Schristos char * condCodes[NUM_EXT_COND];
7475fd0b74Schristos };
7575fd0b74Schristos
7675fd0b74Schristos
7775fd0b74Schristos /* Local data. */
7875fd0b74Schristos
7975fd0b74Schristos /* Extension table. */
8075fd0b74Schristos static struct arcExtMap arc_extension_map;
8175fd0b74Schristos
8275fd0b74Schristos
8375fd0b74Schristos /* Local macros. */
8475fd0b74Schristos
8575fd0b74Schristos /* A hash function used to map instructions into the table. */
8675fd0b74Schristos #define INST_HASH(MAJOR, MINOR) ((((MAJOR) << 3) ^ (MINOR)) & INST_HASH_MASK)
8775fd0b74Schristos
8875fd0b74Schristos
8975fd0b74Schristos /* Local functions. */
9075fd0b74Schristos
9175fd0b74Schristos static void
create_map(unsigned char * block,unsigned long length)9275fd0b74Schristos create_map (unsigned char *block,
9375fd0b74Schristos unsigned long length)
9475fd0b74Schristos {
9575fd0b74Schristos unsigned char *p = block;
9675fd0b74Schristos
9775fd0b74Schristos while (p && p < (block + length))
9875fd0b74Schristos {
9975fd0b74Schristos /* p[0] == length of record
10075fd0b74Schristos p[1] == type of record
10175fd0b74Schristos For instructions:
10275fd0b74Schristos p[2] = opcode
10375fd0b74Schristos p[3] = minor opcode (if opcode == 3)
10475fd0b74Schristos p[4] = flags
10575fd0b74Schristos p[5]+ = name
10675fd0b74Schristos For core regs and condition codes:
10775fd0b74Schristos p[2] = value
10875fd0b74Schristos p[3]+ = name
10975fd0b74Schristos For auxiliary regs:
11075fd0b74Schristos p[2..5] = value
11175fd0b74Schristos p[6]+ = name
11275fd0b74Schristos (value is p[2]<<24|p[3]<<16|p[4]<<8|p[5]). */
11375fd0b74Schristos
11475fd0b74Schristos /* The sequence of records is temrinated by an "empty"
11575fd0b74Schristos record. */
11675fd0b74Schristos if (p[0] == 0)
11775fd0b74Schristos break;
11875fd0b74Schristos
11975fd0b74Schristos switch (p[1])
12075fd0b74Schristos {
12175fd0b74Schristos case EXT_INSTRUCTION:
12275fd0b74Schristos {
12375fd0b74Schristos struct ExtInstruction *insn = XNEW (struct ExtInstruction);
12475fd0b74Schristos int major = p[2];
12575fd0b74Schristos int minor = p[3];
12675fd0b74Schristos struct ExtInstruction **bucket =
12775fd0b74Schristos &arc_extension_map.instructions[INST_HASH (major, minor)];
12875fd0b74Schristos
12975fd0b74Schristos insn->name = xstrdup ((char *) (p + 5));
13075fd0b74Schristos insn->major = major;
13175fd0b74Schristos insn->minor = minor;
13275fd0b74Schristos insn->flags = p[4];
13375fd0b74Schristos insn->next = *bucket;
13475fd0b74Schristos insn->suffix = 0;
13575fd0b74Schristos insn->syntax = 0;
13675fd0b74Schristos insn->modsyn = 0;
13775fd0b74Schristos *bucket = insn;
13875fd0b74Schristos break;
13975fd0b74Schristos }
14075fd0b74Schristos
14175fd0b74Schristos case EXT_CORE_REGISTER:
14275fd0b74Schristos {
14375fd0b74Schristos unsigned char number = p[2];
14475fd0b74Schristos char* name = (char *) (p + 3);
14575fd0b74Schristos
14675fd0b74Schristos arc_extension_map.
14775fd0b74Schristos coreRegisters[number - FIRST_EXTENSION_CORE_REGISTER].number
14875fd0b74Schristos = number;
14975fd0b74Schristos arc_extension_map.
15075fd0b74Schristos coreRegisters[number - FIRST_EXTENSION_CORE_REGISTER].rw
15175fd0b74Schristos = REG_READWRITE;
15275fd0b74Schristos arc_extension_map.
15375fd0b74Schristos coreRegisters[number - FIRST_EXTENSION_CORE_REGISTER].name
15475fd0b74Schristos = xstrdup (name);
15575fd0b74Schristos break;
15675fd0b74Schristos }
15775fd0b74Schristos
15875fd0b74Schristos case EXT_LONG_CORE_REGISTER:
15975fd0b74Schristos {
16075fd0b74Schristos unsigned char number = p[2];
16175fd0b74Schristos char* name = (char *) (p + 7);
16275fd0b74Schristos enum ExtReadWrite rw = p[6];
16375fd0b74Schristos
16475fd0b74Schristos arc_extension_map.
16575fd0b74Schristos coreRegisters[number - FIRST_EXTENSION_CORE_REGISTER].number
16675fd0b74Schristos = number;
16775fd0b74Schristos arc_extension_map.
16875fd0b74Schristos coreRegisters[number - FIRST_EXTENSION_CORE_REGISTER].rw
16975fd0b74Schristos = rw;
17075fd0b74Schristos arc_extension_map.
17175fd0b74Schristos coreRegisters[number - FIRST_EXTENSION_CORE_REGISTER].name
17275fd0b74Schristos = xstrdup (name);
173ede78133Schristos break;
17475fd0b74Schristos }
17575fd0b74Schristos
17675fd0b74Schristos case EXT_COND_CODE:
17775fd0b74Schristos {
17875fd0b74Schristos char *cc_name = xstrdup ((char *) (p + 3));
17975fd0b74Schristos
18075fd0b74Schristos arc_extension_map.
18175fd0b74Schristos condCodes[p[2] - FIRST_EXTENSION_CONDITION_CODE]
18275fd0b74Schristos = cc_name;
18375fd0b74Schristos break;
18475fd0b74Schristos }
18575fd0b74Schristos
18675fd0b74Schristos case EXT_AUX_REGISTER:
18775fd0b74Schristos {
18875fd0b74Schristos /* Trickier -- need to store linked list of these. */
18975fd0b74Schristos struct ExtAuxRegister *newAuxRegister
19075fd0b74Schristos = XNEW (struct ExtAuxRegister);
19175fd0b74Schristos char *aux_name = xstrdup ((char *) (p + 6));
19275fd0b74Schristos
19375fd0b74Schristos newAuxRegister->name = aux_name;
194012573ebSchristos newAuxRegister->address = (((unsigned) p[2] << 24) | (p[3] << 16)
195012573ebSchristos | (p[4] << 8) | p[5]);
19675fd0b74Schristos newAuxRegister->next = arc_extension_map.auxRegisters;
19775fd0b74Schristos arc_extension_map.auxRegisters = newAuxRegister;
19875fd0b74Schristos break;
19975fd0b74Schristos }
20075fd0b74Schristos
20175fd0b74Schristos default:
20275fd0b74Schristos break;
20375fd0b74Schristos }
20475fd0b74Schristos
20575fd0b74Schristos p += p[0]; /* Move on to next record. */
20675fd0b74Schristos }
20775fd0b74Schristos }
20875fd0b74Schristos
20975fd0b74Schristos
21075fd0b74Schristos /* Free memory that has been allocated for the extensions. */
21175fd0b74Schristos
21275fd0b74Schristos static void
destroy_map(void)21375fd0b74Schristos destroy_map (void)
21475fd0b74Schristos {
21575fd0b74Schristos struct ExtAuxRegister *r;
21675fd0b74Schristos unsigned int i;
21775fd0b74Schristos
21875fd0b74Schristos /* Free auxiliary registers. */
21975fd0b74Schristos r = arc_extension_map.auxRegisters;
22075fd0b74Schristos while (r)
22175fd0b74Schristos {
22275fd0b74Schristos /* N.B. after r has been freed, r->next is invalid! */
22375fd0b74Schristos struct ExtAuxRegister* next = r->next;
22475fd0b74Schristos
22575fd0b74Schristos free (r->name);
22675fd0b74Schristos free (r);
22775fd0b74Schristos r = next;
22875fd0b74Schristos }
22975fd0b74Schristos
23075fd0b74Schristos /* Free instructions. */
23175fd0b74Schristos for (i = 0; i < INST_HASH_SIZE; i++)
23275fd0b74Schristos {
23375fd0b74Schristos struct ExtInstruction *insn = arc_extension_map.instructions[i];
23475fd0b74Schristos
23575fd0b74Schristos while (insn)
23675fd0b74Schristos {
23775fd0b74Schristos /* N.B. after insn has been freed, insn->next is invalid! */
23875fd0b74Schristos struct ExtInstruction *next = insn->next;
23975fd0b74Schristos
24075fd0b74Schristos free (insn->name);
24175fd0b74Schristos free (insn);
24275fd0b74Schristos insn = next;
24375fd0b74Schristos }
24475fd0b74Schristos }
24575fd0b74Schristos
24675fd0b74Schristos /* Free core registers. */
24775fd0b74Schristos for (i = 0; i < NUM_EXT_CORE; i++)
24875fd0b74Schristos free (arc_extension_map.coreRegisters[i].name);
24975fd0b74Schristos
25075fd0b74Schristos /* Free condition codes. */
25175fd0b74Schristos for (i = 0; i < NUM_EXT_COND; i++)
25275fd0b74Schristos free (arc_extension_map.condCodes[i]);
25375fd0b74Schristos
25475fd0b74Schristos memset (&arc_extension_map, 0, sizeof (arc_extension_map));
25575fd0b74Schristos }
25675fd0b74Schristos
25775fd0b74Schristos
25875fd0b74Schristos static const char *
ExtReadWrite_image(enum ExtReadWrite val)25975fd0b74Schristos ExtReadWrite_image (enum ExtReadWrite val)
26075fd0b74Schristos {
26175fd0b74Schristos switch (val)
26275fd0b74Schristos {
26375fd0b74Schristos case REG_INVALID : return "INVALID";
26475fd0b74Schristos case REG_READ : return "RO";
26575fd0b74Schristos case REG_WRITE : return "WO";
26675fd0b74Schristos case REG_READWRITE: return "R/W";
26775fd0b74Schristos default : return "???";
26875fd0b74Schristos }
26975fd0b74Schristos }
27075fd0b74Schristos
27175fd0b74Schristos
27275fd0b74Schristos /* Externally visible functions. */
27375fd0b74Schristos
27475fd0b74Schristos /* Get the name of an extension instruction. */
27575fd0b74Schristos
27675fd0b74Schristos const extInstruction_t *
arcExtMap_insn(int opcode,unsigned long long insn)277ede78133Schristos arcExtMap_insn (int opcode, unsigned long long insn)
27875fd0b74Schristos {
27975fd0b74Schristos /* Here the following tasks need to be done. First of all, the
28075fd0b74Schristos opcode stored in the Extension Map is the real opcode. However,
28175fd0b74Schristos the subopcode stored in the instruction to be disassembled is
28275fd0b74Schristos mangled. We pass (in minor opcode), the instruction word. Here
28375fd0b74Schristos we will un-mangle it and get the real subopcode which we can look
28475fd0b74Schristos for in the Extension Map. This function is used both for the
28575fd0b74Schristos ARCTangent and the ARCompact, so we would also need some sort of
28675fd0b74Schristos a way to distinguish between the two architectures. This is
28775fd0b74Schristos because the ARCTangent does not do any of this mangling so we
28875fd0b74Schristos have no issues there. */
28975fd0b74Schristos
29075fd0b74Schristos /* If P[22:23] is 0 or 2 then un-mangle using iiiiiI. If it is 1
29175fd0b74Schristos then use iiiiIi. Now, if P is 3 then check M[5:5] and if it is 0
29275fd0b74Schristos then un-mangle using iiiiiI else iiiiii. */
29375fd0b74Schristos
29475fd0b74Schristos unsigned char minor;
29575fd0b74Schristos extInstruction_t *temp;
29675fd0b74Schristos
29775fd0b74Schristos /* 16-bit instructions. */
29875fd0b74Schristos if (0x08 <= opcode && opcode <= 0x0b)
29975fd0b74Schristos {
30075fd0b74Schristos unsigned char b, c, i;
30175fd0b74Schristos
30275fd0b74Schristos b = (insn & 0x0700) >> 8;
30375fd0b74Schristos c = (insn & 0x00e0) >> 5;
30475fd0b74Schristos i = (insn & 0x001f);
30575fd0b74Schristos
30675fd0b74Schristos if (i)
30775fd0b74Schristos minor = i;
30875fd0b74Schristos else
30975fd0b74Schristos minor = (c == 0x07) ? b : c;
31075fd0b74Schristos }
31175fd0b74Schristos /* 32-bit instructions. */
31275fd0b74Schristos else
31375fd0b74Schristos {
31475fd0b74Schristos unsigned char I, A, B;
31575fd0b74Schristos
31675fd0b74Schristos I = (insn & 0x003f0000) >> 16;
31775fd0b74Schristos A = (insn & 0x0000003f);
31875fd0b74Schristos B = ((insn & 0x07000000) >> 24) | ((insn & 0x00007000) >> 9);
31975fd0b74Schristos
32075fd0b74Schristos if (I != 0x2f)
32175fd0b74Schristos {
32275fd0b74Schristos #ifndef UNMANGLED
32375fd0b74Schristos switch (P)
32475fd0b74Schristos {
32575fd0b74Schristos case 3:
32675fd0b74Schristos if (M)
32775fd0b74Schristos {
32875fd0b74Schristos minor = I;
32975fd0b74Schristos break;
33075fd0b74Schristos }
33175fd0b74Schristos case 0:
33275fd0b74Schristos case 2:
33375fd0b74Schristos minor = (I >> 1) | ((I & 0x1) << 5);
33475fd0b74Schristos break;
33575fd0b74Schristos case 1:
33675fd0b74Schristos minor = (I >> 1) | (I & 0x1) | ((I & 0x2) << 4);
33775fd0b74Schristos }
33875fd0b74Schristos #else
33975fd0b74Schristos minor = I;
34075fd0b74Schristos #endif
34175fd0b74Schristos }
34275fd0b74Schristos else
34375fd0b74Schristos {
34475fd0b74Schristos if (A != 0x3f)
34575fd0b74Schristos minor = A;
34675fd0b74Schristos else
34775fd0b74Schristos minor = B;
34875fd0b74Schristos }
34975fd0b74Schristos }
35075fd0b74Schristos
35175fd0b74Schristos temp = arc_extension_map.instructions[INST_HASH (opcode, minor)];
35275fd0b74Schristos while (temp)
35375fd0b74Schristos {
35475fd0b74Schristos if ((temp->major == opcode) && (temp->minor == minor))
35575fd0b74Schristos {
35675fd0b74Schristos return temp;
35775fd0b74Schristos }
35875fd0b74Schristos temp = temp->next;
35975fd0b74Schristos }
36075fd0b74Schristos
36175fd0b74Schristos return NULL;
36275fd0b74Schristos }
36375fd0b74Schristos
36475fd0b74Schristos /* Get the name of an extension core register. */
36575fd0b74Schristos
36675fd0b74Schristos const char *
arcExtMap_coreRegName(int regnum)36775fd0b74Schristos arcExtMap_coreRegName (int regnum)
36875fd0b74Schristos {
36975fd0b74Schristos if (regnum < FIRST_EXTENSION_CORE_REGISTER
37075fd0b74Schristos || regnum > LAST_EXTENSION_CORE_REGISTER)
37175fd0b74Schristos return NULL;
37275fd0b74Schristos return arc_extension_map.
37375fd0b74Schristos coreRegisters[regnum - FIRST_EXTENSION_CORE_REGISTER].name;
37475fd0b74Schristos }
37575fd0b74Schristos
37675fd0b74Schristos /* Get the access mode of an extension core register. */
37775fd0b74Schristos
37875fd0b74Schristos enum ExtReadWrite
arcExtMap_coreReadWrite(int regnum)37975fd0b74Schristos arcExtMap_coreReadWrite (int regnum)
38075fd0b74Schristos {
38175fd0b74Schristos if (regnum < FIRST_EXTENSION_CORE_REGISTER
38275fd0b74Schristos || regnum > LAST_EXTENSION_CORE_REGISTER)
38375fd0b74Schristos return REG_INVALID;
38475fd0b74Schristos return arc_extension_map.
38575fd0b74Schristos coreRegisters[regnum - FIRST_EXTENSION_CORE_REGISTER].rw;
38675fd0b74Schristos }
38775fd0b74Schristos
38875fd0b74Schristos /* Get the name of an extension condition code. */
38975fd0b74Schristos
39075fd0b74Schristos const char *
arcExtMap_condCodeName(int code)39175fd0b74Schristos arcExtMap_condCodeName (int code)
39275fd0b74Schristos {
39375fd0b74Schristos if (code < FIRST_EXTENSION_CONDITION_CODE
39475fd0b74Schristos || code > LAST_EXTENSION_CONDITION_CODE)
39575fd0b74Schristos return NULL;
39675fd0b74Schristos return arc_extension_map.
39775fd0b74Schristos condCodes[code - FIRST_EXTENSION_CONDITION_CODE];
39875fd0b74Schristos }
39975fd0b74Schristos
40075fd0b74Schristos /* Get the name of an extension auxiliary register. */
40175fd0b74Schristos
40275fd0b74Schristos const char *
arcExtMap_auxRegName(unsigned address)403012573ebSchristos arcExtMap_auxRegName (unsigned address)
40475fd0b74Schristos {
40575fd0b74Schristos /* Walk the list of auxiliary register names and find the name. */
40675fd0b74Schristos struct ExtAuxRegister *r;
40775fd0b74Schristos
40875fd0b74Schristos for (r = arc_extension_map.auxRegisters; r; r = r->next)
40975fd0b74Schristos {
41075fd0b74Schristos if (r->address == address)
41175fd0b74Schristos return (const char *)r->name;
41275fd0b74Schristos }
41375fd0b74Schristos return NULL;
41475fd0b74Schristos }
41575fd0b74Schristos
41675fd0b74Schristos /* Load extensions described in .arcextmap and
41775fd0b74Schristos .gnu.linkonce.arcextmap.* ELF section. */
41875fd0b74Schristos
41975fd0b74Schristos void
build_ARC_extmap(bfd * text_bfd)42075fd0b74Schristos build_ARC_extmap (bfd *text_bfd)
42175fd0b74Schristos {
42275fd0b74Schristos asection *sect;
42375fd0b74Schristos
42475fd0b74Schristos /* The map is built each time gdb loads an executable file - so free
42575fd0b74Schristos any existing map, as the map defined by the new file may differ
42675fd0b74Schristos from the old. */
42775fd0b74Schristos destroy_map ();
42875fd0b74Schristos
42975fd0b74Schristos for (sect = text_bfd->sections; sect != NULL; sect = sect->next)
43075fd0b74Schristos if (!strncmp (sect->name,
43175fd0b74Schristos ".gnu.linkonce.arcextmap.",
43275fd0b74Schristos sizeof (".gnu.linkonce.arcextmap.") - 1)
43375fd0b74Schristos || !strcmp (sect->name,".arcextmap"))
43475fd0b74Schristos {
435012573ebSchristos bfd_size_type count = bfd_section_size (sect);
43675fd0b74Schristos unsigned char* buffer = xmalloc (count);
43775fd0b74Schristos
43875fd0b74Schristos if (buffer)
43975fd0b74Schristos {
44075fd0b74Schristos if (bfd_get_section_contents (text_bfd, sect, buffer, 0, count))
44175fd0b74Schristos create_map (buffer, count);
44275fd0b74Schristos free (buffer);
44375fd0b74Schristos }
44475fd0b74Schristos }
44575fd0b74Schristos }
44675fd0b74Schristos
44775fd0b74Schristos /* Debug function used to dump the ARC information fount in arcextmap
44875fd0b74Schristos sections. */
44975fd0b74Schristos
45075fd0b74Schristos void
dump_ARC_extmap(void)45175fd0b74Schristos dump_ARC_extmap (void)
45275fd0b74Schristos {
45375fd0b74Schristos struct ExtAuxRegister *r;
45475fd0b74Schristos int i;
45575fd0b74Schristos
45675fd0b74Schristos r = arc_extension_map.auxRegisters;
45775fd0b74Schristos
45875fd0b74Schristos while (r)
45975fd0b74Schristos {
460012573ebSchristos printf ("AUX : %s %u\n", r->name, r->address);
46175fd0b74Schristos r = r->next;
46275fd0b74Schristos }
46375fd0b74Schristos
46475fd0b74Schristos for (i = 0; i < INST_HASH_SIZE; i++)
46575fd0b74Schristos {
46675fd0b74Schristos struct ExtInstruction *insn;
46775fd0b74Schristos
46875fd0b74Schristos for (insn = arc_extension_map.instructions[i];
46975fd0b74Schristos insn != NULL; insn = insn->next)
47075fd0b74Schristos {
47175fd0b74Schristos printf ("INST: 0x%02x 0x%02x ", insn->major, insn->minor);
47275fd0b74Schristos switch (insn->flags & ARC_SYNTAX_MASK)
47375fd0b74Schristos {
47475fd0b74Schristos case ARC_SYNTAX_2OP:
47575fd0b74Schristos printf ("SYNTAX_2OP");
47675fd0b74Schristos break;
47775fd0b74Schristos case ARC_SYNTAX_3OP:
47875fd0b74Schristos printf ("SYNTAX_3OP");
47975fd0b74Schristos break;
48075fd0b74Schristos case ARC_SYNTAX_1OP:
48175fd0b74Schristos printf ("SYNTAX_1OP");
48275fd0b74Schristos break;
48375fd0b74Schristos case ARC_SYNTAX_NOP:
48475fd0b74Schristos printf ("SYNTAX_NOP");
48575fd0b74Schristos break;
48675fd0b74Schristos default:
48775fd0b74Schristos printf ("SYNTAX_UNK");
48875fd0b74Schristos break;
48975fd0b74Schristos }
49075fd0b74Schristos
49175fd0b74Schristos if (insn->flags & 0x10)
49275fd0b74Schristos printf ("|MODIFIER");
49375fd0b74Schristos
49475fd0b74Schristos printf (" %s\n", insn->name);
49575fd0b74Schristos }
49675fd0b74Schristos }
49775fd0b74Schristos
49875fd0b74Schristos for (i = 0; i < NUM_EXT_CORE; i++)
49975fd0b74Schristos {
50075fd0b74Schristos struct ExtCoreRegister reg = arc_extension_map.coreRegisters[i];
50175fd0b74Schristos
50275fd0b74Schristos if (reg.name)
50375fd0b74Schristos printf ("CORE: 0x%04x %s %s\n", reg.number,
50475fd0b74Schristos ExtReadWrite_image (reg.rw),
50575fd0b74Schristos reg.name);
50675fd0b74Schristos }
50775fd0b74Schristos
50875fd0b74Schristos for (i = 0; i < NUM_EXT_COND; i++)
50975fd0b74Schristos if (arc_extension_map.condCodes[i])
51075fd0b74Schristos printf ("COND: %s\n", arc_extension_map.condCodes[i]);
51175fd0b74Schristos }
51275fd0b74Schristos
51375fd0b74Schristos /* For a given extension instruction generate the equivalent arc
51475fd0b74Schristos opcode structure. */
51575fd0b74Schristos
51675fd0b74Schristos struct arc_opcode *
arcExtMap_genOpcode(const extInstruction_t * einsn,unsigned arc_target,const char ** errmsg)51775fd0b74Schristos arcExtMap_genOpcode (const extInstruction_t *einsn,
51875fd0b74Schristos unsigned arc_target,
51975fd0b74Schristos const char **errmsg)
52075fd0b74Schristos {
52175fd0b74Schristos struct arc_opcode *q, *arc_ext_opcodes = NULL;
52275fd0b74Schristos const unsigned char *lflags_f;
52375fd0b74Schristos const unsigned char *lflags_ccf;
52475fd0b74Schristos int count;
52575fd0b74Schristos
52675fd0b74Schristos /* Check for the class to see how many instructions we generate. */
52775fd0b74Schristos switch (einsn->flags & ARC_SYNTAX_MASK)
52875fd0b74Schristos {
52975fd0b74Schristos case ARC_SYNTAX_3OP:
53075fd0b74Schristos count = (einsn->modsyn & ARC_OP1_MUST_BE_IMM) ? 10 : 20;
53175fd0b74Schristos break;
53275fd0b74Schristos case ARC_SYNTAX_2OP:
53375fd0b74Schristos count = (einsn->flags & 0x10) ? 7 : 6;
53475fd0b74Schristos break;
53575fd0b74Schristos case ARC_SYNTAX_1OP:
53675fd0b74Schristos count = 3;
53775fd0b74Schristos break;
53875fd0b74Schristos case ARC_SYNTAX_NOP:
53975fd0b74Schristos count = 1;
54075fd0b74Schristos break;
54175fd0b74Schristos default:
54275fd0b74Schristos count = 0;
54375fd0b74Schristos break;
54475fd0b74Schristos }
54575fd0b74Schristos
54675fd0b74Schristos /* Allocate memory. */
54775fd0b74Schristos arc_ext_opcodes = (struct arc_opcode *)
54875fd0b74Schristos xmalloc ((count + 1) * sizeof (*arc_ext_opcodes));
54975fd0b74Schristos
55075fd0b74Schristos if (arc_ext_opcodes == NULL)
55175fd0b74Schristos {
55275fd0b74Schristos *errmsg = "Virtual memory exhausted";
55375fd0b74Schristos return NULL;
55475fd0b74Schristos }
55575fd0b74Schristos
55675fd0b74Schristos /* Generate the patterns. */
55775fd0b74Schristos q = arc_ext_opcodes;
55875fd0b74Schristos
55975fd0b74Schristos if (einsn->suffix)
56075fd0b74Schristos {
56175fd0b74Schristos lflags_f = flags_none;
56275fd0b74Schristos lflags_ccf = flags_none;
56375fd0b74Schristos }
56475fd0b74Schristos else
56575fd0b74Schristos {
56675fd0b74Schristos lflags_f = flags_f;
56775fd0b74Schristos lflags_ccf = flags_ccf;
56875fd0b74Schristos }
56975fd0b74Schristos
57075fd0b74Schristos if (einsn->suffix & ARC_SUFFIX_COND)
57175fd0b74Schristos lflags_ccf = flags_cc;
57275fd0b74Schristos if (einsn->suffix & ARC_SUFFIX_FLAG)
57375fd0b74Schristos {
57475fd0b74Schristos lflags_f = flags_f;
57575fd0b74Schristos lflags_ccf = flags_f;
57675fd0b74Schristos }
57775fd0b74Schristos if (einsn->suffix & (ARC_SUFFIX_FLAG | ARC_SUFFIX_COND))
57875fd0b74Schristos lflags_ccf = flags_ccf;
57975fd0b74Schristos
58075fd0b74Schristos if (einsn->flags & ARC_SYNTAX_2OP
58175fd0b74Schristos && !(einsn->flags & 0x10))
58275fd0b74Schristos {
58375fd0b74Schristos /* Regular 2OP instruction. */
58475fd0b74Schristos if (einsn->suffix & ARC_SUFFIX_COND)
58575fd0b74Schristos *errmsg = "Suffix SUFFIX_COND ignored";
58675fd0b74Schristos
58775fd0b74Schristos INSERT_XOP (q, einsn->name,
58875fd0b74Schristos INSN2OP_BC (einsn->major, einsn->minor), MINSN2OP_BC,
58975fd0b74Schristos arc_target, arg_32bit_rbrc, lflags_f);
59075fd0b74Schristos
59175fd0b74Schristos INSERT_XOP (q, einsn->name,
59275fd0b74Schristos INSN2OP_0C (einsn->major, einsn->minor), MINSN2OP_0C,
59375fd0b74Schristos arc_target, arg_32bit_zarc, lflags_f);
59475fd0b74Schristos
59575fd0b74Schristos INSERT_XOP (q, einsn->name,
59675fd0b74Schristos INSN2OP_BU (einsn->major, einsn->minor), MINSN2OP_BU,
59775fd0b74Schristos arc_target, arg_32bit_rbu6, lflags_f);
59875fd0b74Schristos
59975fd0b74Schristos INSERT_XOP (q, einsn->name,
60075fd0b74Schristos INSN2OP_0U (einsn->major, einsn->minor), MINSN2OP_0U,
60175fd0b74Schristos arc_target, arg_32bit_zau6, lflags_f);
60275fd0b74Schristos
60375fd0b74Schristos INSERT_XOP (q, einsn->name,
60475fd0b74Schristos INSN2OP_BL (einsn->major, einsn->minor), MINSN2OP_BL,
60575fd0b74Schristos arc_target, arg_32bit_rblimm, lflags_f);
60675fd0b74Schristos
60775fd0b74Schristos INSERT_XOP (q, einsn->name,
60875fd0b74Schristos INSN2OP_0L (einsn->major, einsn->minor), MINSN2OP_0L,
60975fd0b74Schristos arc_target, arg_32bit_zalimm, lflags_f);
61075fd0b74Schristos }
61175fd0b74Schristos else if (einsn->flags & (0x10 | ARC_SYNTAX_2OP))
61275fd0b74Schristos {
61375fd0b74Schristos /* This is actually a 3OP pattern. The first operand is
61475fd0b74Schristos immplied and is set to zero. */
61575fd0b74Schristos INSERT_XOP (q, einsn->name,
61675fd0b74Schristos INSN3OP_0BC (einsn->major, einsn->minor), MINSN3OP_0BC,
61775fd0b74Schristos arc_target, arg_32bit_rbrc, lflags_f);
61875fd0b74Schristos
61975fd0b74Schristos INSERT_XOP (q, einsn->name,
62075fd0b74Schristos INSN3OP_0BU (einsn->major, einsn->minor), MINSN3OP_0BU,
62175fd0b74Schristos arc_target, arg_32bit_rbu6, lflags_f);
62275fd0b74Schristos
62375fd0b74Schristos INSERT_XOP (q, einsn->name,
62475fd0b74Schristos INSN3OP_0BL (einsn->major, einsn->minor), MINSN3OP_0BL,
62575fd0b74Schristos arc_target, arg_32bit_rblimm, lflags_f);
62675fd0b74Schristos
62775fd0b74Schristos INSERT_XOP (q, einsn->name,
62875fd0b74Schristos INSN3OP_C0LC (einsn->major, einsn->minor), MINSN3OP_C0LC,
62975fd0b74Schristos arc_target, arg_32bit_limmrc, lflags_ccf);
63075fd0b74Schristos
63175fd0b74Schristos INSERT_XOP (q, einsn->name,
63275fd0b74Schristos INSN3OP_C0LU (einsn->major, einsn->minor), MINSN3OP_C0LU,
63375fd0b74Schristos arc_target, arg_32bit_limmu6, lflags_ccf);
63475fd0b74Schristos
63575fd0b74Schristos INSERT_XOP (q, einsn->name,
63675fd0b74Schristos INSN3OP_0LS (einsn->major, einsn->minor), MINSN3OP_0LS,
63775fd0b74Schristos arc_target, arg_32bit_limms12, lflags_f);
63875fd0b74Schristos
63975fd0b74Schristos INSERT_XOP (q, einsn->name,
64075fd0b74Schristos INSN3OP_C0LL (einsn->major, einsn->minor), MINSN3OP_C0LL,
64175fd0b74Schristos arc_target, arg_32bit_limmlimm, lflags_ccf);
64275fd0b74Schristos }
64375fd0b74Schristos else if (einsn->flags & ARC_SYNTAX_3OP
64475fd0b74Schristos && !(einsn->modsyn & ARC_OP1_MUST_BE_IMM))
64575fd0b74Schristos {
64675fd0b74Schristos /* Regular 3OP instruction. */
64775fd0b74Schristos INSERT_XOP (q, einsn->name,
64875fd0b74Schristos INSN3OP_ABC (einsn->major, einsn->minor), MINSN3OP_ABC,
64975fd0b74Schristos arc_target, arg_32bit_rarbrc, lflags_f);
65075fd0b74Schristos
65175fd0b74Schristos INSERT_XOP (q, einsn->name,
65275fd0b74Schristos INSN3OP_0BC (einsn->major, einsn->minor), MINSN3OP_0BC,
65375fd0b74Schristos arc_target, arg_32bit_zarbrc, lflags_f);
65475fd0b74Schristos
65575fd0b74Schristos INSERT_XOP (q, einsn->name,
65675fd0b74Schristos INSN3OP_CBBC (einsn->major, einsn->minor), MINSN3OP_CBBC,
65775fd0b74Schristos arc_target, arg_32bit_rbrbrc, lflags_ccf);
65875fd0b74Schristos
65975fd0b74Schristos INSERT_XOP (q, einsn->name,
66075fd0b74Schristos INSN3OP_ABU (einsn->major, einsn->minor), MINSN3OP_ABU,
66175fd0b74Schristos arc_target, arg_32bit_rarbu6, lflags_f);
66275fd0b74Schristos
66375fd0b74Schristos INSERT_XOP (q, einsn->name,
66475fd0b74Schristos INSN3OP_0BU (einsn->major, einsn->minor), MINSN3OP_0BU,
66575fd0b74Schristos arc_target, arg_32bit_zarbu6, lflags_f);
66675fd0b74Schristos
66775fd0b74Schristos INSERT_XOP (q, einsn->name,
66875fd0b74Schristos INSN3OP_CBBU (einsn->major, einsn->minor), MINSN3OP_CBBU,
66975fd0b74Schristos arc_target, arg_32bit_rbrbu6, lflags_ccf);
67075fd0b74Schristos
67175fd0b74Schristos INSERT_XOP (q, einsn->name,
67275fd0b74Schristos INSN3OP_BBS (einsn->major, einsn->minor), MINSN3OP_BBS,
67375fd0b74Schristos arc_target, arg_32bit_rbrbs12, lflags_f);
67475fd0b74Schristos
67575fd0b74Schristos INSERT_XOP (q, einsn->name,
67675fd0b74Schristos INSN3OP_ALC (einsn->major, einsn->minor), MINSN3OP_ALC,
67775fd0b74Schristos arc_target, arg_32bit_ralimmrc, lflags_f);
67875fd0b74Schristos
67975fd0b74Schristos INSERT_XOP (q, einsn->name,
68075fd0b74Schristos INSN3OP_ABL (einsn->major, einsn->minor), MINSN3OP_ABL,
68175fd0b74Schristos arc_target, arg_32bit_rarblimm, lflags_f);
68275fd0b74Schristos
68375fd0b74Schristos INSERT_XOP (q, einsn->name,
68475fd0b74Schristos INSN3OP_0LC (einsn->major, einsn->minor), MINSN3OP_0LC,
68575fd0b74Schristos arc_target, arg_32bit_zalimmrc, lflags_f);
68675fd0b74Schristos
68775fd0b74Schristos INSERT_XOP (q, einsn->name,
68875fd0b74Schristos INSN3OP_0BL (einsn->major, einsn->minor), MINSN3OP_0BL,
68975fd0b74Schristos arc_target, arg_32bit_zarblimm, lflags_f);
69075fd0b74Schristos
69175fd0b74Schristos INSERT_XOP (q, einsn->name,
69275fd0b74Schristos INSN3OP_C0LC (einsn->major, einsn->minor), MINSN3OP_C0LC,
69375fd0b74Schristos arc_target, arg_32bit_zalimmrc, lflags_ccf);
69475fd0b74Schristos
69575fd0b74Schristos INSERT_XOP (q, einsn->name,
69675fd0b74Schristos INSN3OP_CBBL (einsn->major, einsn->minor), MINSN3OP_CBBL,
69775fd0b74Schristos arc_target, arg_32bit_rbrblimm, lflags_ccf);
69875fd0b74Schristos
69975fd0b74Schristos INSERT_XOP (q, einsn->name,
70075fd0b74Schristos INSN3OP_ALU (einsn->major, einsn->minor), MINSN3OP_ALU,
70175fd0b74Schristos arc_target, arg_32bit_ralimmu6, lflags_f);
70275fd0b74Schristos
70375fd0b74Schristos INSERT_XOP (q, einsn->name,
70475fd0b74Schristos INSN3OP_0LU (einsn->major, einsn->minor), MINSN3OP_0LU,
70575fd0b74Schristos arc_target, arg_32bit_zalimmu6, lflags_f);
70675fd0b74Schristos
70775fd0b74Schristos INSERT_XOP (q, einsn->name,
70875fd0b74Schristos INSN3OP_C0LU (einsn->major, einsn->minor), MINSN3OP_C0LU,
70975fd0b74Schristos arc_target, arg_32bit_zalimmu6, lflags_ccf);
71075fd0b74Schristos
71175fd0b74Schristos INSERT_XOP (q, einsn->name,
71275fd0b74Schristos INSN3OP_0LS (einsn->major, einsn->minor), MINSN3OP_0LS,
71375fd0b74Schristos arc_target, arg_32bit_zalimms12, lflags_f);
71475fd0b74Schristos
71575fd0b74Schristos INSERT_XOP (q, einsn->name,
71675fd0b74Schristos INSN3OP_ALL (einsn->major, einsn->minor), MINSN3OP_ALL,
71775fd0b74Schristos arc_target, arg_32bit_ralimmlimm, lflags_f);
71875fd0b74Schristos
71975fd0b74Schristos INSERT_XOP (q, einsn->name,
72075fd0b74Schristos INSN3OP_0LL (einsn->major, einsn->minor), MINSN3OP_0LL,
72175fd0b74Schristos arc_target, arg_32bit_zalimmlimm, lflags_f);
72275fd0b74Schristos
72375fd0b74Schristos INSERT_XOP (q, einsn->name,
72475fd0b74Schristos INSN3OP_C0LL (einsn->major, einsn->minor), MINSN3OP_C0LL,
72575fd0b74Schristos arc_target, arg_32bit_zalimmlimm, lflags_ccf);
72675fd0b74Schristos }
72775fd0b74Schristos else if (einsn->flags & ARC_SYNTAX_3OP)
72875fd0b74Schristos {
72975fd0b74Schristos /* 3OP instruction which accepts only zero as first
73075fd0b74Schristos argument. */
73175fd0b74Schristos INSERT_XOP (q, einsn->name,
73275fd0b74Schristos INSN3OP_0BC (einsn->major, einsn->minor), MINSN3OP_0BC,
73375fd0b74Schristos arc_target, arg_32bit_zarbrc, lflags_f);
73475fd0b74Schristos
73575fd0b74Schristos INSERT_XOP (q, einsn->name,
73675fd0b74Schristos INSN3OP_0BU (einsn->major, einsn->minor), MINSN3OP_0BU,
73775fd0b74Schristos arc_target, arg_32bit_zarbu6, lflags_f);
73875fd0b74Schristos
73975fd0b74Schristos INSERT_XOP (q, einsn->name,
74075fd0b74Schristos INSN3OP_0LC (einsn->major, einsn->minor), MINSN3OP_0LC,
74175fd0b74Schristos arc_target, arg_32bit_zalimmrc, lflags_f);
74275fd0b74Schristos
74375fd0b74Schristos INSERT_XOP (q, einsn->name,
74475fd0b74Schristos INSN3OP_0BL (einsn->major, einsn->minor), MINSN3OP_0BL,
74575fd0b74Schristos arc_target, arg_32bit_zarblimm, lflags_f);
74675fd0b74Schristos
74775fd0b74Schristos INSERT_XOP (q, einsn->name,
74875fd0b74Schristos INSN3OP_C0LC (einsn->major, einsn->minor), MINSN3OP_C0LC,
74975fd0b74Schristos arc_target, arg_32bit_zalimmrc, lflags_ccf);
75075fd0b74Schristos
75175fd0b74Schristos INSERT_XOP (q, einsn->name,
75275fd0b74Schristos INSN3OP_0LU (einsn->major, einsn->minor), MINSN3OP_0LU,
75375fd0b74Schristos arc_target, arg_32bit_zalimmu6, lflags_f);
75475fd0b74Schristos
75575fd0b74Schristos INSERT_XOP (q, einsn->name,
75675fd0b74Schristos INSN3OP_C0LU (einsn->major, einsn->minor), MINSN3OP_C0LU,
75775fd0b74Schristos arc_target, arg_32bit_zalimmu6, lflags_ccf);
75875fd0b74Schristos
75975fd0b74Schristos INSERT_XOP (q, einsn->name,
76075fd0b74Schristos INSN3OP_0LS (einsn->major, einsn->minor), MINSN3OP_0LS,
76175fd0b74Schristos arc_target, arg_32bit_zalimms12, lflags_f);
76275fd0b74Schristos
76375fd0b74Schristos INSERT_XOP (q, einsn->name,
76475fd0b74Schristos INSN3OP_0LL (einsn->major, einsn->minor), MINSN3OP_0LL,
76575fd0b74Schristos arc_target, arg_32bit_zalimmlimm, lflags_f);
76675fd0b74Schristos
76775fd0b74Schristos INSERT_XOP (q, einsn->name,
76875fd0b74Schristos INSN3OP_C0LL (einsn->major, einsn->minor), MINSN3OP_C0LL,
76975fd0b74Schristos arc_target, arg_32bit_zalimmlimm, lflags_ccf);
77075fd0b74Schristos }
77175fd0b74Schristos else if (einsn->flags & ARC_SYNTAX_1OP)
77275fd0b74Schristos {
77375fd0b74Schristos if (einsn->suffix & ARC_SUFFIX_COND)
77475fd0b74Schristos *errmsg = "Suffix SUFFIX_COND ignored";
77575fd0b74Schristos
77675fd0b74Schristos INSERT_XOP (q, einsn->name,
77775fd0b74Schristos INSN2OP (einsn->major, 0x3F) | FIELDB (einsn->minor),
77875fd0b74Schristos MINSN2OP_0C, arc_target, arg_32bit_rc, lflags_f);
77975fd0b74Schristos
78075fd0b74Schristos INSERT_XOP (q, einsn->name,
78175fd0b74Schristos INSN2OP (einsn->major, 0x3F) | FIELDB (einsn->minor)
78275fd0b74Schristos | (0x01 << 22), MINSN2OP_0U, arc_target, arg_32bit_u6,
78375fd0b74Schristos lflags_f);
78475fd0b74Schristos
78575fd0b74Schristos INSERT_XOP (q, einsn->name,
78675fd0b74Schristos INSN2OP (einsn->major, 0x3F) | FIELDB (einsn->minor)
78775fd0b74Schristos | FIELDC (62), MINSN2OP_0L, arc_target, arg_32bit_limm,
78875fd0b74Schristos lflags_f);
78975fd0b74Schristos
79075fd0b74Schristos }
79175fd0b74Schristos else if (einsn->flags & ARC_SYNTAX_NOP)
79275fd0b74Schristos {
79375fd0b74Schristos if (einsn->suffix & ARC_SUFFIX_COND)
79475fd0b74Schristos *errmsg = "Suffix SUFFIX_COND ignored";
79575fd0b74Schristos
79675fd0b74Schristos INSERT_XOP (q, einsn->name,
79775fd0b74Schristos INSN2OP (einsn->major, 0x3F) | FIELDB (einsn->minor)
79875fd0b74Schristos | (0x01 << 22), MINSN2OP_0L, arc_target, arg_none, lflags_f);
79975fd0b74Schristos }
80075fd0b74Schristos else
80175fd0b74Schristos {
80275fd0b74Schristos *errmsg = "Unknown syntax";
80375fd0b74Schristos return NULL;
80475fd0b74Schristos }
80575fd0b74Schristos
80675fd0b74Schristos /* End marker. */
80775fd0b74Schristos memset (q, 0, sizeof (*arc_ext_opcodes));
80875fd0b74Schristos
80975fd0b74Schristos return arc_ext_opcodes;
81075fd0b74Schristos }
811