1 /* Subroutines used for ISR of Andes NDS32 cpu for GNU compiler
2    Copyright (C) 2012-2022 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.  */
44 static 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 
56 static void
nds32_interrupt_attribute_parse_string(const char * original_str,const char * func_name,unsigned int s_level)57 nds32_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 
147 static void
nds32_exception_attribute_parse_string(const char * original_str,const char * func_name,unsigned int s_level)148 nds32_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 
237 static void
nds32_reset_attribute_parse_string(const char * original_str,const char * func_name)238 nds32_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.  */
302 static void
nds32_emit_section_head_template(char section_name[],char symbol_name[],int align_value,bool object_p)303 nds32_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.  */
322 static void
nds32_emit_section_tail_template(char symbol_name[])323 nds32_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.  */
329 static void
nds32_emit_isr_jmptbl_section(int vector_id)330 nds32_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.  */
357 static void
nds32_emit_isr_vector_section(int vector_id)358 nds32_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.  */
515 static void
nds32_emit_isr_reset_content(void)516 nds32_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.  */
598 void
nds32_check_isr_attrs_conflict(tree func_decl,tree func_attrs)599 nds32_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 register 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().  */
660 void
nds32_construct_isr_vectors_information(tree func_attrs,const char * func_name)661 nds32_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 
852 void
nds32_asm_file_start_for_isr(void)853 nds32_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 
nds32_asm_file_end_for_isr(void)871 void 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.  */
917 bool
nds32_isr_function_p(tree func)918 nds32_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.  */
941 bool
nds32_isr_function_critical_p(tree func)942 nds32_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