1185377Ssam/* ARC target-dependent stuff. Extension structure access functions
2187831Ssam   Copyright 1995, 1997, 2000, 2001, 2004, 2005
3185377Ssam   Free Software Foundation, Inc.
4185377Ssam
5185377Ssam   This file is part of GDB.
6185377Ssam
7185377Ssam   This program is free software; you can redistribute it and/or modify
8185377Ssam   it under the terms of the GNU General Public License as published by
9185377Ssam   the Free Software Foundation; either version 2 of the License, or
10185377Ssam   (at your option) any later version.
11185377Ssam
12185377Ssam   This program is distributed in the hope that it will be useful,
13185377Ssam   but WITHOUT ANY WARRANTY; without even the implied warranty of
14185377Ssam   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15185377Ssam   GNU General Public License for more details.
16185377Ssam
17186020Ssam   You should have received a copy of the GNU General Public License
18185377Ssam   along with this program; if not, write to the Free Software
19185377Ssam   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
20185377Ssam
21185377Ssam#include "sysdep.h"
22185377Ssam#include <stdlib.h>
23185377Ssam#include <stdio.h>
24185377Ssam#include "bfd.h"
25185377Ssam#include "arc-ext.h"
26185377Ssam#include "libiberty.h"
27185377Ssam
28185377Ssam/* Extension structure  */
29185377Ssamstatic struct arcExtMap arc_extension_map;
30187831Ssam
31220442Sadrian/* Get the name of an extension instruction.  */
32187831Ssam
33185377Ssamconst char *
34185377SsamarcExtMap_instName(int opcode, int minor, int *flags)
35185377Ssam{
36185377Ssam    if (opcode == 3)
37185377Ssam      {
38185377Ssam	/* FIXME: ??? need to also check 0/1/2 in bit0 for (3f) brk/sleep/swi  */
39185377Ssam	if (minor < 0x09 || minor == 0x3f)
40185377Ssam	  return 0;
41185377Ssam	else
42185377Ssam	  opcode = 0x1f - 0x10 + minor - 0x09 + 1;
43185377Ssam      }
44185377Ssam    else
45185377Ssam      if (opcode < 0x10)
46185377Ssam	return 0;
47185377Ssam    else
48185377Ssam      opcode -= 0x10;
49185377Ssam    if (!arc_extension_map.instructions[opcode])
50185377Ssam      return 0;
51185377Ssam    *flags = arc_extension_map.instructions[opcode]->flags;
52185377Ssam    return arc_extension_map.instructions[opcode]->name;
53188771Ssam}
54188771Ssam
55188771Ssam/* Get the name of an extension core register.  */
56188771Ssam
57188771Ssamconst char *
58185377SsamarcExtMap_coreRegName(int value)
59185377Ssam{
60185380Ssam  if (value < 32)
61185380Ssam    return 0;
62185380Ssam  return arc_extension_map.coreRegisters[value-32];
63185377Ssam}
64185377Ssam
65185377Ssam/* Get the name of an extension condition code.  */
66185377Ssam
67185377Ssamconst char *
68185377SsamarcExtMap_condCodeName(int value)
69185377Ssam{
70185377Ssam  if (value < 16)
71185377Ssam    return 0;
72185377Ssam  return arc_extension_map.condCodes[value-16];
73185377Ssam}
74185377Ssam
75185377Ssam/* Get the name of an extension aux register.  */
76185377Ssam
77185406Ssamconst char *
78185406SsamarcExtMap_auxRegName(long address)
79185406Ssam{
80185406Ssam  /* walk the list of aux reg names and find the name  */
81185418Ssam  struct ExtAuxRegister *r;
82185406Ssam
83185406Ssam  for (r = arc_extension_map.auxRegisters; r; r = r->next) {
84217624Sadrian    if (r->address == address)
85217624Sadrian      return (const char *) r->name;
86185406Ssam  }
87185406Ssam  return 0;
88185418Ssam}
89188504Ssam
90185418Ssam/* Recursively free auxilliary register strcture pointers until
91185406Ssam   the list is empty.  */
92185406Ssam
93185406Ssamstatic void
94188500Ssamclean_aux_registers(struct ExtAuxRegister *r)
95185406Ssam{
96185377Ssam  if (r -> next)
97185377Ssam    {
98185406Ssam      clean_aux_registers( r->next);
99185406Ssam      free(r -> name);
100185406Ssam      free(r -> next);
101185406Ssam      r ->next = NULL;
102185406Ssam    }
103185418Ssam  else
104185406Ssam    free(r -> name);
105185406Ssam}
106185406Ssam
107185406Ssam/* Free memory that has been allocated for the extensions.  */
108185418Ssam
109186020Ssamstatic void
110186020Ssamcleanup_ext_map(void)
111185406Ssam{
112185406Ssam  struct ExtAuxRegister *r;
113185406Ssam  struct ExtInstruction *insn;
114186020Ssam  int i;
115185406Ssam
116185406Ssam  /* clean aux reg structure  */
117185406Ssam  r = arc_extension_map.auxRegisters;
118185406Ssam  if (r)
119185406Ssam    {
120187831Ssam      (clean_aux_registers(r));
121187831Ssam      free(r);
122187831Ssam    }
123187831Ssam
124187831Ssam  /* clean instructions  */
125185377Ssam  for (i = 0; i < NUM_EXT_INST; i++)
126187831Ssam    {
127187831Ssam      insn = arc_extension_map.instructions[i];
128187831Ssam      if (insn)
129187831Ssam	free(insn->name);
130187831Ssam    }
131187831Ssam
132187831Ssam  /* clean core reg struct  */
133187831Ssam  for (i = 0; i < NUM_EXT_CORE; i++)
134185377Ssam    {
135187831Ssam      if (arc_extension_map.coreRegisters[i])
136185377Ssam	free(arc_extension_map.coreRegisters[i]);
137187831Ssam    }
138187831Ssam
139187831Ssam  for (i = 0; i < NUM_EXT_COND; i++) {
140220442Sadrian    if (arc_extension_map.condCodes[i])
141187831Ssam      free(arc_extension_map.condCodes[i]);
142185377Ssam  }
143185377Ssam
144185377Ssam  memset(&arc_extension_map, 0, sizeof(struct arcExtMap));
145185377Ssam}
146220442Sadrian
147220444Sadrianint
148220444SadrianarcExtMap_add(void *base, unsigned long length)
149220442Sadrian{
150187831Ssam  unsigned char *block = base;
151185377Ssam  unsigned char *p = block;
152185377Ssam
153187831Ssam  /* Clean up and reset everything if needed.  */
154187831Ssam  cleanup_ext_map();
155187831Ssam
156187831Ssam  while (p && p < (block + length))
157187831Ssam    {
158187831Ssam      /* p[0] == length of record
159187831Ssam	 p[1] == type of record
160187831Ssam	 For instructions:
161187831Ssam	   p[2]  = opcode
162187831Ssam	   p[3]  = minor opcode (if opcode == 3)
163185377Ssam	   p[4]  = flags
164185377Ssam	   p[5]+ = name
165185377Ssam	 For core regs and condition codes:
166185377Ssam	   p[2]  = value
167185377Ssam	   p[3]+ = name
168185377Ssam	 For aux regs:
169185377Ssam	   p[2..5] = value
170185377Ssam	   p[6]+   = name
171185377Ssam	 (value is p[2]<<24|p[3]<<16|p[4]<<8|p[5])  */
172185377Ssam
173185377Ssam      if (p[0] == 0)
174185377Ssam	return -1;
175185377Ssam
176185377Ssam      switch (p[1])
177185377Ssam	{
178185377Ssam	case EXT_INSTRUCTION:
179185377Ssam	  {
180185377Ssam	    char opcode = p[2];
181185377Ssam	    char minor  = p[3];
182185377Ssam	    char * insn_name = (char *) xmalloc(( (int)*p-5) * sizeof(char));
183185377Ssam	    struct ExtInstruction * insn =
184185377Ssam	      (struct ExtInstruction *) xmalloc(sizeof(struct ExtInstruction));
185185377Ssam
186185377Ssam	    if (opcode==3)
187221603Sadrian	      opcode = 0x1f - 0x10 + minor - 0x09 + 1;
188185377Ssam	    else
189185377Ssam	      opcode -= 0x10;
190185377Ssam	    insn -> flags = (char) *(p+4);
191185377Ssam	    strcpy (insn_name, (char *) (p+5));
192185377Ssam	    insn -> name = insn_name;
193185377Ssam	    arc_extension_map.instructions[(int) opcode] = insn;
194185377Ssam	  }
195185377Ssam	  break;
196185377Ssam
197185377Ssam	case EXT_CORE_REGISTER:
198185377Ssam	  {
199185377Ssam	    char * core_name = (char *) xmalloc(((int)*p-3) * sizeof(char));
200185377Ssam
201221603Sadrian	    strcpy(core_name, (char *) (p+3));
202185377Ssam	    arc_extension_map.coreRegisters[p[2]-32] = core_name;
203222584Sadrian	  }
204185377Ssam	  break;
205185377Ssam
206222584Sadrian	case EXT_COND_CODE:
207195114Ssam	  {
208218436Sadrian	    char * cc_name = (char *) xmalloc( ((int)*p-3) * sizeof(char));
209220034Sadrian	    strcpy(cc_name, (char *) (p+3));
210221667Sadrian	    arc_extension_map.condCodes[p[2]-16] = cc_name;
211225444Sadrian	  }
212225444Sadrian	  break;
213185377Ssam
214185377Ssam	case EXT_AUX_REGISTER:
215185377Ssam	  {
216185377Ssam	    /* trickier -- need to store linked list to these  */
217185377Ssam	    struct ExtAuxRegister *newAuxRegister =
218185377Ssam	      (struct ExtAuxRegister *)malloc(sizeof(struct ExtAuxRegister));
219185377Ssam	    char * aux_name = (char *) xmalloc ( ((int)*p-6) * sizeof(char));
220185377Ssam
221185377Ssam	    strcpy (aux_name, (char *) (p+6));
222185377Ssam	    newAuxRegister->name = aux_name;
223185377Ssam	    newAuxRegister->address = p[2]<<24 | p[3]<<16 | p[4]<<8  | p[5];
224185377Ssam	    newAuxRegister->next = arc_extension_map.auxRegisters;
225192396Ssam	    arc_extension_map.auxRegisters = newAuxRegister;
226218150Sadrian	  }
227218150Sadrian	  break;
228185377Ssam
229185377Ssam	default:
230187831Ssam	  return -1;
231187831Ssam
232185377Ssam	}
233185377Ssam      p += p[0]; /* move to next record  */
234185380Ssam    }
235185380Ssam
236185380Ssam  return 0;
237185380Ssam}
238185380Ssam
239185380Ssam/* Load hw extension descibed in .extArcMap ELF section.  */
240185380Ssam
241185380Ssamvoid
242185380Ssambuild_ARC_extmap (text_bfd)
243185380Ssam  bfd *text_bfd;
244185380Ssam{
245185380Ssam  char *arcExtMap;
246185380Ssam  bfd_size_type count;
247185380Ssam  asection *p;
248185380Ssam
249185380Ssam  for (p = text_bfd->sections; p != NULL; p = p->next)
250185380Ssam    if (!strcmp (p->name, ".arcextmap"))
251185377Ssam      {
252185377Ssam        count = bfd_get_section_size (p);
253185377Ssam        arcExtMap = (char *) xmalloc (count);
254185377Ssam        if (bfd_get_section_contents (text_bfd, p, (PTR) arcExtMap, 0, count))
255185377Ssam          {
256185377Ssam            arcExtMap_add ((PTR) arcExtMap, count);
257185377Ssam            break;
258185377Ssam          }
259185377Ssam        free ((PTR) arcExtMap);
260185377Ssam      }
261185377Ssam}
262185377Ssam