1/* Subroutines used for ISR of Andes NDS32 cpu for GNU compiler
2   Copyright (C) 2012-2020 Free Software Foundation, Inc.
3   Contributed by Andes Technology Corporation.
4
5   This file is part of GCC.
6
7   GCC is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published
9   by the Free Software Foundation; either version 3, or (at your
10   option) any later version.
11
12   GCC is distributed in the hope that it will be useful, but WITHOUT
13   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15   License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with GCC; see the file COPYING3.  If not see
19   <http://www.gnu.org/licenses/>.  */
20
21/* ------------------------------------------------------------------------ */
22
23#define IN_TARGET_CODE 1
24
25#include "config.h"
26#include "system.h"
27#include "coretypes.h"
28#include "backend.h"
29#include "target.h"
30#include "rtl.h"
31#include "tree.h"
32#include "stringpool.h"
33#include "attribs.h"
34#include "diagnostic-core.h"
35#include "output.h"
36
37/* ------------------------------------------------------------------------ */
38
39/* Refer to nds32.h, there are maximum 73 isr vectors in nds32 architecture.
40   0 for reset handler with __attribute__((reset())),
41   1-8 for exception handler with __attribute__((exception(1,...,8))),
42   and 9-72 for interrupt handler with __attribute__((interrupt(0,...,63))).
43   We use an array to record essential information for each vector.  */
44static struct nds32_isr_info nds32_isr_vectors[NDS32_N_ISR_VECTORS];
45
46/* ------------------------------------------------------------- */
47/* FIXME:
48   FOR BACKWARD COMPATIBILITY, we need to support following patterns:
49
50       __attribute__((interrupt("XXX;YYY;id=ZZZ")))
51       __attribute__((exception("XXX;YYY;id=ZZZ")))
52       __attribute__((reset("vectors=XXX;nmi_func=YYY;warm_func=ZZZ")))
53
54   We provide several functions to parse the strings.  */
55
56static void
57nds32_interrupt_attribute_parse_string (const char *original_str,
58					const char *func_name,
59					unsigned int s_level)
60{
61  char target_str[100];
62  enum nds32_isr_save_reg save_reg;
63  enum nds32_isr_nested_type nested_type;
64
65  char *save_all_regs_str, *save_caller_regs_str;
66  char *nested_str, *not_nested_str, *ready_nested_str, *critical_str;
67  char *id_str, *value_str;
68
69  /* Copy original string into a character array so that
70     the string APIs can handle it.  */
71  strcpy (target_str, original_str);
72
73  /* 1. Detect 'save_all_regs'    : NDS32_SAVE_ALL
74	       'save_caller_regs' : NDS32_PARTIAL_SAVE */
75  save_all_regs_str    = strstr (target_str, "save_all_regs");
76  save_caller_regs_str = strstr (target_str, "save_caller_regs");
77
78  /* Note that if no argument is found,
79     use NDS32_PARTIAL_SAVE by default.  */
80  if (save_all_regs_str)
81    save_reg = NDS32_SAVE_ALL;
82  else if (save_caller_regs_str)
83    save_reg = NDS32_PARTIAL_SAVE;
84  else
85    save_reg = NDS32_PARTIAL_SAVE;
86
87  /* 2. Detect 'nested'       : NDS32_NESTED
88	       'not_nested'   : NDS32_NOT_NESTED
89	       'ready_nested' : NDS32_NESTED_READY
90	       'critical'     : NDS32_CRITICAL */
91  nested_str       = strstr (target_str, "nested");
92  not_nested_str   = strstr (target_str, "not_nested");
93  ready_nested_str = strstr (target_str, "ready_nested");
94  critical_str     = strstr (target_str, "critical");
95
96  /* Note that if no argument is found,
97     use NDS32_NOT_NESTED by default.
98     Also, since 'not_nested' and 'ready_nested' both contains
99     'nested' string, we check 'nested' with lowest priority.  */
100  if (not_nested_str)
101    nested_type = NDS32_NOT_NESTED;
102  else if (ready_nested_str)
103    nested_type = NDS32_NESTED_READY;
104  else if (nested_str)
105    nested_type = NDS32_NESTED;
106  else if (critical_str)
107    nested_type = NDS32_CRITICAL;
108  else
109    nested_type = NDS32_NOT_NESTED;
110
111  /* 3. Traverse each id value and set corresponding information.  */
112  id_str = strstr (target_str, "id=");
113
114  /* If user forgets to assign 'id', issue an error message.  */
115  if (id_str == NULL)
116    error ("require id argument in the string");
117  /* Extract the value_str first.  */
118  id_str    = strtok (id_str, "=");
119  value_str = strtok (NULL, ";");
120
121  /* Pick up the first id value token.  */
122  value_str = strtok (value_str, ",");
123  while (value_str != NULL)
124    {
125      int i;
126      i = atoi (value_str);
127
128      /* For interrupt(0..63), the actual vector number is (9..72).  */
129      i = i + 9;
130      if (i < 9 || i > 72)
131	error ("invalid id value for interrupt attribute");
132
133      /* Setup nds32_isr_vectors[] array.  */
134      nds32_isr_vectors[i].category = NDS32_ISR_INTERRUPT;
135      strcpy (nds32_isr_vectors[i].func_name, func_name);
136      nds32_isr_vectors[i].save_reg = save_reg;
137      nds32_isr_vectors[i].nested_type = nested_type;
138      nds32_isr_vectors[i].security_level = s_level;
139
140      /* Fetch next token.  */
141      value_str = strtok (NULL, ",");
142    }
143
144  return;
145}
146
147static void
148nds32_exception_attribute_parse_string (const char *original_str,
149					const char *func_name,
150					unsigned int s_level)
151{
152  char target_str[100];
153  enum nds32_isr_save_reg save_reg;
154  enum nds32_isr_nested_type nested_type;
155
156  char *save_all_regs_str, *save_caller_regs_str;
157  char *nested_str, *not_nested_str, *ready_nested_str, *critical_str;
158  char *id_str, *value_str;
159
160  /* Copy original string into a character array so that
161     the string APIs can handle it.  */
162  strcpy (target_str, original_str);
163
164  /* 1. Detect 'save_all_regs'    : NDS32_SAVE_ALL
165	       'save_caller_regs' : NDS32_PARTIAL_SAVE */
166  save_all_regs_str    = strstr (target_str, "save_all_regs");
167  save_caller_regs_str = strstr (target_str, "save_caller_regs");
168
169  /* Note that if no argument is found,
170     use NDS32_PARTIAL_SAVE by default.  */
171  if (save_all_regs_str)
172    save_reg = NDS32_SAVE_ALL;
173  else if (save_caller_regs_str)
174    save_reg = NDS32_PARTIAL_SAVE;
175  else
176    save_reg = NDS32_PARTIAL_SAVE;
177
178  /* 2. Detect 'nested'       : NDS32_NESTED
179	       'not_nested'   : NDS32_NOT_NESTED
180	       'ready_nested' : NDS32_NESTED_READY
181	       'critical'     : NDS32_CRITICAL */
182  nested_str       = strstr (target_str, "nested");
183  not_nested_str   = strstr (target_str, "not_nested");
184  ready_nested_str = strstr (target_str, "ready_nested");
185  critical_str     = strstr (target_str, "critical");
186
187  /* Note that if no argument is found,
188     use NDS32_NOT_NESTED by default.
189     Also, since 'not_nested' and 'ready_nested' both contains
190     'nested' string, we check 'nested' with lowest priority.  */
191  if (not_nested_str)
192    nested_type = NDS32_NOT_NESTED;
193  else if (ready_nested_str)
194    nested_type = NDS32_NESTED_READY;
195  else if (nested_str)
196    nested_type = NDS32_NESTED;
197  else if (critical_str)
198    nested_type = NDS32_CRITICAL;
199  else
200    nested_type = NDS32_NOT_NESTED;
201
202  /* 3. Traverse each id value and set corresponding information.  */
203  id_str = strstr (target_str, "id=");
204
205  /* If user forgets to assign 'id', issue an error message.  */
206  if (id_str == NULL)
207    error ("require id argument in the string");
208  /* Extract the value_str first.  */
209  id_str    = strtok (id_str, "=");
210  value_str = strtok (NULL, ";");
211
212  /* Pick up the first id value token.  */
213  value_str = strtok (value_str, ",");
214  while (value_str != NULL)
215    {
216      int i;
217      i = atoi (value_str);
218
219      /* For exception(1..8), the actual vector number is (1..8).  */
220      if (i < 1 || i > 8)
221	error ("invalid id value for exception attribute");
222
223      /* Setup nds32_isr_vectors[] array.  */
224      nds32_isr_vectors[i].category = NDS32_ISR_EXCEPTION;
225      strcpy (nds32_isr_vectors[i].func_name, func_name);
226      nds32_isr_vectors[i].save_reg = save_reg;
227      nds32_isr_vectors[i].nested_type = nested_type;
228      nds32_isr_vectors[i].security_level = s_level;
229
230      /* Fetch next token.  */
231      value_str = strtok (NULL, ",");
232    }
233
234  return;
235}
236
237static void
238nds32_reset_attribute_parse_string (const char *original_str,
239				    const char *func_name)
240{
241  char target_str[100];
242  char *vectors_str, *nmi_str, *warm_str, *value_str;
243
244  /* Deal with reset attribute.  Its vector number is always 0.  */
245  nds32_isr_vectors[0].category = NDS32_ISR_RESET;
246
247
248  /* 1. Parse 'vectors=XXXX'.  */
249
250  /* Copy original string into a character array so that
251     the string APIs can handle it.  */
252  strcpy (target_str, original_str);
253  vectors_str = strstr (target_str, "vectors=");
254  /* The total vectors = interrupt + exception numbers + reset.
255     There are 8 exception and 1 reset in nds32 architecture.
256     If user forgets to assign 'vectors', user default 16 interrupts.  */
257  if (vectors_str != NULL)
258    {
259      /* Extract the value_str.  */
260      vectors_str = strtok (vectors_str, "=");
261      value_str  = strtok (NULL, ";");
262      nds32_isr_vectors[0].total_n_vectors = atoi (value_str) + 8 + 1;
263    }
264  else
265    nds32_isr_vectors[0].total_n_vectors = 16 + 8 + 1;
266  strcpy (nds32_isr_vectors[0].func_name, func_name);
267
268
269  /* 2. Parse 'nmi_func=YYYY'.  */
270
271  /* Copy original string into a character array so that
272     the string APIs can handle it.  */
273  strcpy (target_str, original_str);
274  nmi_str = strstr (target_str, "nmi_func=");
275  if (nmi_str != NULL)
276    {
277      /* Extract the value_str.  */
278      nmi_str = strtok (nmi_str, "=");
279      value_str  = strtok (NULL, ";");
280      strcpy (nds32_isr_vectors[0].nmi_name, value_str);
281    }
282
283  /* 3. Parse 'warm_func=ZZZZ'.  */
284
285  /* Copy original string into a character array so that
286     the string APIs can handle it.  */
287  strcpy (target_str, original_str);
288  warm_str = strstr (target_str, "warm_func=");
289  if (warm_str != NULL)
290    {
291      /* Extract the value_str.  */
292      warm_str = strtok (warm_str, "=");
293      value_str  = strtok (NULL, ";");
294      strcpy (nds32_isr_vectors[0].warm_name, value_str);
295    }
296
297  return;
298}
299/* ------------------------------------------------------------- */
300
301/* A helper function to emit section head template.  */
302static void
303nds32_emit_section_head_template (char section_name[],
304				  char symbol_name[],
305				  int align_value,
306				  bool object_p)
307{
308  const char *flags_str;
309  const char *type_str;
310
311  flags_str = (object_p) ? "\"a\"" : "\"ax\"";
312  type_str = (object_p) ? "@object" : "@function";
313
314  fprintf (asm_out_file, "\t.section\t%s, %s\n", section_name, flags_str);
315  fprintf (asm_out_file, "\t.align\t%d\n", align_value);
316  fprintf (asm_out_file, "\t.global\t%s\n", symbol_name);
317  fprintf (asm_out_file, "\t.type\t%s, %s\n", symbol_name, type_str);
318  fprintf (asm_out_file, "%s:\n", symbol_name);
319}
320
321/* A helper function to emit section tail template.  */
322static void
323nds32_emit_section_tail_template (char symbol_name[])
324{
325  fprintf (asm_out_file, "\t.size\t%s, .-%s\n", symbol_name, symbol_name);
326}
327
328/* Function to emit isr jump table section.  */
329static void
330nds32_emit_isr_jmptbl_section (int vector_id)
331{
332  char section_name[100];
333  char symbol_name[100];
334
335  /* A critical isr does not need jump table section because
336     its behavior is not performed by two-level handler.  */
337  if (nds32_isr_vectors[vector_id].nested_type == NDS32_CRITICAL)
338    {
339      fprintf (asm_out_file, "\t! The vector %02d is a critical isr !\n",
340			     vector_id);
341      return;
342    }
343
344  /* Prepare jmptbl section and symbol name.  */
345  snprintf (section_name, sizeof (section_name),
346	    ".nds32_jmptbl.%02d", vector_id);
347  snprintf (symbol_name, sizeof (symbol_name),
348	    "_nds32_jmptbl_%02d", vector_id);
349
350  nds32_emit_section_head_template (section_name, symbol_name, 2, true);
351  fprintf (asm_out_file, "\t.word\t%s\n",
352			 nds32_isr_vectors[vector_id].func_name);
353  nds32_emit_section_tail_template (symbol_name);
354}
355
356/* Function to emit isr vector section.  */
357static void
358nds32_emit_isr_vector_section (int vector_id)
359{
360  unsigned int vector_number_offset = 0;
361  const char *c_str = "CATEGORY";
362  const char *sr_str = "SR";
363  const char *nt_str = "NT";
364  char first_level_handler_name[100];
365  char section_name[100];
366  char symbol_name[100];
367
368  /* Set the vector number offset so that we can calculate
369     the value that user specifies in the attribute.
370     We also prepare the category string for first level handler name.  */
371  switch (nds32_isr_vectors[vector_id].category)
372    {
373    case NDS32_ISR_INTERRUPT:
374      vector_number_offset = 9;
375      c_str = "i";
376      break;
377    case NDS32_ISR_EXCEPTION:
378      vector_number_offset = 0;
379      c_str = "e";
380      break;
381    case NDS32_ISR_NONE:
382    case NDS32_ISR_RESET:
383      /* Normally it should not be here.  */
384      gcc_unreachable ();
385      break;
386    }
387
388  /* Prepare save reg string for first level handler name.  */
389  switch (nds32_isr_vectors[vector_id].save_reg)
390    {
391    case NDS32_SAVE_ALL:
392      sr_str = "sa";
393      break;
394    case NDS32_PARTIAL_SAVE:
395      sr_str = "ps";
396      break;
397    }
398
399  /* Prepare nested type string for first level handler name.  */
400  switch (nds32_isr_vectors[vector_id].nested_type)
401    {
402    case NDS32_NESTED:
403      nt_str = "ns";
404      break;
405    case NDS32_NOT_NESTED:
406      nt_str = "nn";
407      break;
408    case NDS32_NESTED_READY:
409      nt_str = "nr";
410      break;
411    case NDS32_CRITICAL:
412      /* The critical isr is not performed by two-level handler.  */
413      nt_str = "";
414      break;
415    }
416
417  /* Now we can create first level handler name.  */
418  if (nds32_isr_vectors[vector_id].security_level == 0)
419    {
420      /* For security level 0, use normal first level handler name.  */
421      snprintf (first_level_handler_name, sizeof (first_level_handler_name),
422		"_nds32_%s_%s_%s", c_str, sr_str, nt_str);
423    }
424  else
425    {
426      /* For security level 1-3, use corresponding spl_1, spl_2, or spl_3.  */
427      snprintf (first_level_handler_name, sizeof (first_level_handler_name),
428		"_nds32_spl_%d", nds32_isr_vectors[vector_id].security_level);
429    }
430
431  /* Prepare vector section and symbol name.  */
432  snprintf (section_name, sizeof (section_name),
433	    ".nds32_vector.%02d", vector_id);
434  snprintf (symbol_name, sizeof (symbol_name),
435	    "_nds32_vector_%02d", vector_id);
436
437
438  /* Everything is ready.  We can start emit vector section content.  */
439  nds32_emit_section_head_template (section_name, symbol_name,
440				    floor_log2 (nds32_isr_vector_size), false);
441
442  /* First we check if it is a critical isr.
443     If so, jump to user handler directly; otherwise, the instructions
444     in the vector section may be different according to the vector size.  */
445  if (nds32_isr_vectors[vector_id].nested_type == NDS32_CRITICAL)
446    {
447      /* This block is for critical isr.  Jump to user handler directly.  */
448      fprintf (asm_out_file, "\tj\t%s ! jump to user handler directly\n",
449			     nds32_isr_vectors[vector_id].func_name);
450    }
451  else if (nds32_isr_vector_size == 4)
452    {
453      /* This block is for 4-byte vector size.
454	 Hardware $VID support is necessary and only one instruction
455	 is needed in vector section.  */
456      fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n",
457			     first_level_handler_name);
458    }
459  else
460    {
461      /* This block is for 16-byte vector size.
462	 There is NO hardware $VID so that we need several instructions
463	 such as pushing GPRs and preparing software vid at vector section.
464	 For pushing GPRs, there are four variations for
465	 16-byte vector content and we have to handle each combination.
466	 For preparing software vid, note that the vid need to
467	 be substracted vector_number_offset.  */
468      if (TARGET_REDUCED_REGS)
469	{
470	  if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
471	    {
472	      /* Case of reduced set registers and save_all attribute.  */
473	      fprintf (asm_out_file, "\t! reduced set regs + save_all\n");
474	      fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0xf\n");
475	      fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r10, 0x0\n");
476
477	    }
478	  else
479	    {
480	      /* Case of reduced set registers and partial_save attribute.  */
481	      fprintf (asm_out_file, "\t! reduced set regs + partial_save\n");
482	      fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0x2\n");
483	      fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
484	    }
485	}
486      else
487	{
488	  if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
489	    {
490	      /* Case of full set registers and save_all attribute.  */
491	      fprintf (asm_out_file, "\t! full set regs + save_all\n");
492	      fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r27, 0xf\n");
493	    }
494	  else
495	    {
496	      /* Case of full set registers and partial_save attribute.  */
497	      fprintf (asm_out_file, "\t! full set regs + partial_save\n");
498	      fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r27, 0x2\n");
499	      fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
500	    }
501	}
502
503      fprintf (asm_out_file, "\tmovi\t$r0, %d ! preparing software vid\n",
504			     vector_id - vector_number_offset);
505      fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n",
506			     first_level_handler_name);
507    }
508
509  nds32_emit_section_tail_template (symbol_name);
510}
511
512/* Function to emit isr reset handler content.
513   Including all jmptbl/vector references, jmptbl section,
514   vector section, nmi handler section, and warm handler section.  */
515static void
516nds32_emit_isr_reset_content (void)
517{
518  unsigned int i;
519  unsigned int total_n_vectors;
520  char reset_handler_name[100];
521  char section_name[100];
522  char symbol_name[100];
523
524  total_n_vectors = nds32_isr_vectors[0].total_n_vectors;
525
526  fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - BEGIN !\n");
527
528  /* Create references in .rodata according to total number of vectors.  */
529  fprintf (asm_out_file, "\t.section\t.rodata\n");
530  fprintf (asm_out_file, "\t.align\t2\n");
531
532  /* Emit jmptbl references.  */
533  fprintf (asm_out_file, "\t ! references to jmptbl section entries\n");
534  for (i = 0; i < total_n_vectors; i++)
535    fprintf (asm_out_file, "\t.word\t_nds32_jmptbl_%02d\n", i);
536
537  /* Emit vector references.  */
538  fprintf (asm_out_file, "\t ! references to vector section entries\n");
539  for (i = 0; i < total_n_vectors; i++)
540    fprintf (asm_out_file, "\t.word\t_nds32_vector_%02d\n", i);
541
542  /* Emit jmptbl_00 section.  */
543  snprintf (section_name, sizeof (section_name), ".nds32_jmptbl.00");
544  snprintf (symbol_name, sizeof (symbol_name), "_nds32_jmptbl_00");
545
546  fprintf (asm_out_file, "\t! ....................................\n");
547  nds32_emit_section_head_template (section_name, symbol_name, 2, true);
548  fprintf (asm_out_file, "\t.word\t%s\n",
549			 nds32_isr_vectors[0].func_name);
550  nds32_emit_section_tail_template (symbol_name);
551
552  /* Emit vector_00 section.  */
553  snprintf (section_name, sizeof (section_name), ".nds32_vector.00");
554  snprintf (symbol_name, sizeof (symbol_name), "_nds32_vector_00");
555  snprintf (reset_handler_name, sizeof (reset_handler_name),
556	    "_nds32_reset");
557
558  fprintf (asm_out_file, "\t! ....................................\n");
559  nds32_emit_section_head_template (section_name, symbol_name,
560				    floor_log2 (nds32_isr_vector_size), false);
561  fprintf (asm_out_file, "\tj\t%s ! jump to reset handler\n",
562			 reset_handler_name);
563  nds32_emit_section_tail_template (symbol_name);
564
565  /* Emit nmi handler section.  */
566  snprintf (section_name, sizeof (section_name), ".nds32_nmih");
567  snprintf (symbol_name, sizeof (symbol_name), "_nds32_nmih");
568
569  fprintf (asm_out_file, "\t! ....................................\n");
570  nds32_emit_section_head_template (section_name, symbol_name, 2, true);
571  fprintf (asm_out_file, "\t.word\t%s\n",
572			 (strlen (nds32_isr_vectors[0].nmi_name) == 0)
573			 ? "0"
574			 : nds32_isr_vectors[0].nmi_name);
575  nds32_emit_section_tail_template (symbol_name);
576
577  /* Emit warm handler section.  */
578  snprintf (section_name, sizeof (section_name), ".nds32_wrh");
579  snprintf (symbol_name, sizeof (symbol_name), "_nds32_wrh");
580
581  fprintf (asm_out_file, "\t! ....................................\n");
582  nds32_emit_section_head_template (section_name, symbol_name, 2, true);
583  fprintf (asm_out_file, "\t.word\t%s\n",
584			 (strlen (nds32_isr_vectors[0].warm_name) == 0)
585			 ? "0"
586			 : nds32_isr_vectors[0].warm_name);
587  nds32_emit_section_tail_template (symbol_name);
588
589  fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - END !\n");
590}
591
592/* Function for nds32_merge_decl_attributes() and nds32_insert_attributes()
593   to check if there are any conflict isr-specific attributes being set.
594   We need to check:
595     1. Only 'save_all' or 'partial_save' in the attributes.
596     2. Only 'nested', 'not_nested', or 'nested_ready' in the attributes.
597     3. Only 'interrupt', 'exception', or 'reset' in the attributes.  */
598void
599nds32_check_isr_attrs_conflict (tree func_decl, tree func_attrs)
600{
601  int save_all_p, partial_save_p;
602  int nested_p, not_nested_p, nested_ready_p, critical_p;
603  int intr_p, excp_p, reset_p;
604
605  /* Initialize variables.  */
606  save_all_p = partial_save_p = 0;
607  nested_p = not_nested_p = nested_ready_p = critical_p = 0;
608  intr_p = excp_p = reset_p = 0;
609
610  /* We must check at MOST one attribute to set save-reg.  */
611  if (lookup_attribute ("save_all", func_attrs))
612    save_all_p = 1;
613  if (lookup_attribute ("partial_save", func_attrs))
614    partial_save_p = 1;
615
616  if ((save_all_p + partial_save_p) > 1)
617    error ("multiple save reg attributes to function %qD", func_decl);
618
619  /* We must check at MOST one attribute to set nested-type.  */
620  if (lookup_attribute ("nested", func_attrs))
621    nested_p = 1;
622  if (lookup_attribute ("not_nested", func_attrs))
623    not_nested_p = 1;
624  if (lookup_attribute ("nested_ready", func_attrs))
625    nested_ready_p = 1;
626  if (lookup_attribute ("critical", func_attrs))
627    critical_p = 1;
628
629  if ((nested_p + not_nested_p + nested_ready_p + critical_p) > 1)
630    error ("multiple nested types attributes to function %qD", func_decl);
631
632  /* We must check at MOST one attribute to
633     set interrupt/exception/reset.  */
634  if (lookup_attribute ("interrupt", func_attrs))
635    intr_p = 1;
636  if (lookup_attribute ("exception", func_attrs))
637    excp_p = 1;
638  if (lookup_attribute ("reset", func_attrs))
639    reset_p = 1;
640
641  if ((intr_p + excp_p + reset_p) > 1)
642    error ("multiple interrupt attributes to function %qD", func_decl);
643
644  /* Do not allow isr attributes under linux toolchain.  */
645  if (TARGET_LINUX_ABI && intr_p)
646      error ("cannot use interrupt attributes to function %qD "
647	     "under linux toolchain", func_decl);
648  if (TARGET_LINUX_ABI && excp_p)
649      error ("cannot use exception attributes to function %qD "
650	     "under linux toolchain", func_decl);
651  if (TARGET_LINUX_ABI && reset_p)
652      error ("cannot use reset attributes to function %qD "
653	     "under linux toolchain", func_decl);
654}
655
656/* Function to construct isr vectors information array.
657   We DO NOT HAVE TO check if the attributes are valid
658   because those works are supposed to be done on
659   nds32_merge_decl_attributes() and nds32_insert_attributes().  */
660void
661nds32_construct_isr_vectors_information (tree func_attrs,
662					 const char *func_name)
663{
664  tree save_all, partial_save;
665  tree nested, not_nested, nested_ready, critical;
666  tree intr, excp, reset;
667
668  tree secure;
669  tree security_level_list;
670  tree security_level;
671  unsigned int s_level;
672
673  save_all     = lookup_attribute ("save_all", func_attrs);
674  partial_save = lookup_attribute ("partial_save", func_attrs);
675
676  nested       = lookup_attribute ("nested", func_attrs);
677  not_nested   = lookup_attribute ("not_nested", func_attrs);
678  nested_ready = lookup_attribute ("nested_ready", func_attrs);
679  critical     = lookup_attribute ("critical", func_attrs);
680
681  intr  = lookup_attribute ("interrupt", func_attrs);
682  excp  = lookup_attribute ("exception", func_attrs);
683  reset = lookup_attribute ("reset", func_attrs);
684
685  /* If there is no interrupt/exception/reset, we can return immediately.  */
686  if (!intr && !excp && !reset)
687    return;
688
689  /* At first, we need to retrieve security level.  */
690  secure = lookup_attribute ("secure", func_attrs);
691  if (secure != NULL)
692    {
693      security_level_list = TREE_VALUE (secure);
694      security_level = TREE_VALUE (security_level_list);
695      s_level = TREE_INT_CST_LOW (security_level);
696    }
697  else
698    {
699      /* If there is no secure attribute, the security level is set by
700	 nds32_isr_secure_level, which is controlled by -misr-secure=X option.
701	 By default nds32_isr_secure_level should be 0.  */
702      s_level = nds32_isr_secure_level;
703    }
704
705  /* ------------------------------------------------------------- */
706  /* FIXME:
707     FOR BACKWARD COMPATIBILITY, we need to support following patterns:
708
709	 __attribute__((interrupt("XXX;YYY;id=ZZZ")))
710	 __attribute__((exception("XXX;YYY;id=ZZZ")))
711	 __attribute__((reset("vectors=XXX;nmi_func=YYY;warm_func=ZZZ")))
712
713     If interrupt/exception/reset appears and its argument is a
714     STRING_CST, we will parse string with some auxiliary functions
715     which set necessary isr information in the nds32_isr_vectors[] array.
716     After that, we can return immediately to avoid new-syntax isr
717     information construction.  */
718  if (intr != NULL_TREE
719      && TREE_CODE (TREE_VALUE (TREE_VALUE (intr))) == STRING_CST)
720    {
721      tree string_arg = TREE_VALUE (TREE_VALUE (intr));
722      nds32_interrupt_attribute_parse_string (TREE_STRING_POINTER (string_arg),
723					      func_name,
724					      s_level);
725      return;
726    }
727  if (excp != NULL_TREE
728      && TREE_CODE (TREE_VALUE (TREE_VALUE (excp))) == STRING_CST)
729    {
730      tree string_arg = TREE_VALUE (TREE_VALUE (excp));
731      nds32_exception_attribute_parse_string (TREE_STRING_POINTER (string_arg),
732					      func_name,
733					      s_level);
734      return;
735    }
736  if (reset != NULL_TREE
737      && TREE_CODE (TREE_VALUE (TREE_VALUE (reset))) == STRING_CST)
738    {
739      tree string_arg = TREE_VALUE (TREE_VALUE (reset));
740      nds32_reset_attribute_parse_string (TREE_STRING_POINTER (string_arg),
741					  func_name);
742      return;
743    }
744  /* ------------------------------------------------------------- */
745
746  /* If we are here, either we have interrupt/exception,
747     or reset attribute.  */
748  if (intr || excp)
749    {
750      tree id_list;
751
752      /* Prepare id list so that we can traverse and set vector id.  */
753      id_list = (intr) ? (TREE_VALUE (intr)) : (TREE_VALUE (excp));
754
755      while (id_list)
756	{
757	  tree id;
758	  int vector_id;
759	  unsigned int vector_number_offset;
760
761	  /* The way to handle interrupt or exception is the same,
762	     we just need to take care of actual vector number.
763	     For interrupt(0..63), the actual vector number is (9..72).
764	     For exception(1..8), the actual vector number is (1..8).  */
765	  vector_number_offset = (intr) ? (9) : (0);
766
767	  /* Pick up each vector id value.  */
768	  id = TREE_VALUE (id_list);
769	  /* Add vector_number_offset to get actual vector number.  */
770	  vector_id = TREE_INT_CST_LOW (id) + vector_number_offset;
771
772	  /* Set security level.  */
773	  nds32_isr_vectors[vector_id].security_level = s_level;
774
775	  /* Enable corresponding vector and set function name.  */
776	  nds32_isr_vectors[vector_id].category = (intr)
777						  ? (NDS32_ISR_INTERRUPT)
778						  : (NDS32_ISR_EXCEPTION);
779	  strcpy (nds32_isr_vectors[vector_id].func_name, func_name);
780
781	  /* Set register saving scheme.  */
782	  if (save_all)
783	    nds32_isr_vectors[vector_id].save_reg = NDS32_SAVE_ALL;
784	  else if (partial_save)
785	    nds32_isr_vectors[vector_id].save_reg = NDS32_PARTIAL_SAVE;
786
787	  /* Set nested type.  */
788	  if (nested)
789	    nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED;
790	  else if (not_nested)
791	    nds32_isr_vectors[vector_id].nested_type = NDS32_NOT_NESTED;
792	  else if (nested_ready)
793	    nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED_READY;
794	  else if (critical)
795	    nds32_isr_vectors[vector_id].nested_type = NDS32_CRITICAL;
796
797	  /* Advance to next id.  */
798	  id_list = TREE_CHAIN (id_list);
799	}
800    }
801  else
802    {
803      tree id_list;
804      tree id;
805      tree nmi, warm;
806
807      /* Deal with reset attribute.  Its vector number is always 0.  */
808      nds32_isr_vectors[0].category = NDS32_ISR_RESET;
809
810      /* Prepare id_list and identify id value so that
811	 we can set total number of vectors.  */
812      id_list = TREE_VALUE (reset);
813      id = TREE_VALUE (id_list);
814
815      /* The total vectors = interrupt + exception numbers + reset.
816	 There are 8 exception and 1 reset in nds32 architecture.  */
817      nds32_isr_vectors[0].total_n_vectors = TREE_INT_CST_LOW (id) + 8 + 1;
818      strcpy (nds32_isr_vectors[0].func_name, func_name);
819
820      /* Retrieve nmi and warm function.  */
821      nmi  = lookup_attribute ("nmi", func_attrs);
822      warm = lookup_attribute ("warm", func_attrs);
823
824      if (nmi != NULL_TREE)
825	{
826	  tree nmi_func_list;
827	  tree nmi_func;
828
829	  nmi_func_list = TREE_VALUE (nmi);
830	  nmi_func = TREE_VALUE (nmi_func_list);
831
832	  /* Record nmi function name.  */
833	  strcpy (nds32_isr_vectors[0].nmi_name,
834		  IDENTIFIER_POINTER (nmi_func));
835	}
836
837      if (warm != NULL_TREE)
838	{
839	  tree warm_func_list;
840	  tree warm_func;
841
842	  warm_func_list = TREE_VALUE (warm);
843	  warm_func = TREE_VALUE (warm_func_list);
844
845	  /* Record warm function name.  */
846	  strcpy (nds32_isr_vectors[0].warm_name,
847		  IDENTIFIER_POINTER (warm_func));
848	}
849    }
850}
851
852void
853nds32_asm_file_start_for_isr (void)
854{
855  int i;
856
857  /* Initialize isr vector information array before compiling functions.  */
858  for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
859    {
860      nds32_isr_vectors[i].category = NDS32_ISR_NONE;
861      strcpy (nds32_isr_vectors[i].func_name, "");
862      nds32_isr_vectors[i].save_reg = NDS32_PARTIAL_SAVE;
863      nds32_isr_vectors[i].nested_type = NDS32_NOT_NESTED;
864      nds32_isr_vectors[i].security_level = 0;
865      nds32_isr_vectors[i].total_n_vectors = 0;
866      strcpy (nds32_isr_vectors[i].nmi_name, "");
867      strcpy (nds32_isr_vectors[i].warm_name, "");
868    }
869}
870
871void nds32_asm_file_end_for_isr (void)
872{
873  int i;
874
875  /* If all the vectors are NDS32_ISR_NONE, we can return immediately.  */
876  for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
877    if (nds32_isr_vectors[i].category != NDS32_ISR_NONE)
878      break;
879
880  if (i == NDS32_N_ISR_VECTORS)
881    return;
882
883  /* At least one vector is NOT NDS32_ISR_NONE,
884     we should output isr vector information.  */
885  fprintf (asm_out_file, "\t! ------------------------------------\n");
886  fprintf (asm_out_file, "\t! The isr vector information:\n");
887  fprintf (asm_out_file, "\t! ------------------------------------\n");
888
889  /* Check reset handler first.  Its vector number is always 0.  */
890  if (nds32_isr_vectors[0].category == NDS32_ISR_RESET)
891    {
892      nds32_emit_isr_reset_content ();
893      fprintf (asm_out_file, "\t! ------------------------------------\n");
894    }
895
896  /* Check other vectors, starting from vector number 1.  */
897  for (i = 1; i < NDS32_N_ISR_VECTORS; i++)
898    {
899      if (nds32_isr_vectors[i].category == NDS32_ISR_INTERRUPT
900	  || nds32_isr_vectors[i].category == NDS32_ISR_EXCEPTION)
901	{
902	  /* Found one vector which is interupt or exception.
903	     Output its jmptbl and vector section content.  */
904	  fprintf (asm_out_file, "\t! interrupt/exception vector %02d\n", i);
905	  fprintf (asm_out_file, "\t! security level: %d\n",
906		   nds32_isr_vectors[i].security_level);
907	  fprintf (asm_out_file, "\t! ------------------------------------\n");
908	  nds32_emit_isr_jmptbl_section (i);
909	  fprintf (asm_out_file, "\t! ....................................\n");
910	  nds32_emit_isr_vector_section (i);
911	  fprintf (asm_out_file, "\t! ------------------------------------\n");
912	}
913    }
914}
915
916/* Return true if FUNC is a isr function.  */
917bool
918nds32_isr_function_p (tree func)
919{
920  tree t_intr;
921  tree t_excp;
922  tree t_reset;
923
924  tree attrs;
925
926  if (TREE_CODE (func) != FUNCTION_DECL)
927    abort ();
928
929  attrs = DECL_ATTRIBUTES (func);
930
931  t_intr  = lookup_attribute ("interrupt", attrs);
932  t_excp  = lookup_attribute ("exception", attrs);
933  t_reset = lookup_attribute ("reset", attrs);
934
935  return ((t_intr != NULL_TREE)
936	  || (t_excp != NULL_TREE)
937	  || (t_reset != NULL_TREE));
938}
939
940/* Return true if FUNC is a isr function with critical attribute.  */
941bool
942nds32_isr_function_critical_p (tree func)
943{
944  tree t_intr;
945  tree t_excp;
946  tree t_critical;
947
948  tree attrs;
949
950  if (TREE_CODE (func) != FUNCTION_DECL)
951    abort ();
952
953  attrs = DECL_ATTRIBUTES (func);
954
955  t_intr  = lookup_attribute ("interrupt", attrs);
956  t_excp  = lookup_attribute ("exception", attrs);
957
958  t_critical = lookup_attribute ("critical", attrs);
959
960  /* If both interrupt and exception attribute does not appear,
961     we can return false immediately.  */
962  if ((t_intr == NULL_TREE) && (t_excp == NULL_TREE))
963    return false;
964
965  /* Here we can guarantee either interrupt or ecxception attribute
966     does exist, so further check critical attribute.
967     If it also appears, we can return true.  */
968  if (t_critical != NULL_TREE)
969    return true;
970
971  /* ------------------------------------------------------------- */
972  /* FIXME:
973     FOR BACKWARD COMPATIBILITY, we need to handle string type.
974     If the string 'critical' appears in the interrupt/exception
975     string argument, we can return true.  */
976  if (t_intr != NULL_TREE || t_excp != NULL_TREE)
977    {
978      char target_str[100];
979      char *critical_str;
980      tree t_check;
981      tree string_arg;
982
983      t_check = t_intr ? t_intr : t_excp;
984      if (TREE_CODE (TREE_VALUE (TREE_VALUE (t_check))) == STRING_CST)
985	{
986	  string_arg = TREE_VALUE (TREE_VALUE (t_check));
987	  strcpy (target_str, TREE_STRING_POINTER (string_arg));
988	  critical_str = strstr (target_str, "critical");
989
990	  /* Found 'critical' string, so return true.  */
991	  if (critical_str)
992	    return true;
993	}
994    }
995  /* ------------------------------------------------------------- */
996
997  /* Other cases, this isr function is not critical type.  */
998  return false;
999}
1000
1001/* ------------------------------------------------------------- */
1002