]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/nds32/nds32-isr.c
[NDS32] Implement more C ISR extension.
[thirdparty/gcc.git] / gcc / config / nds32 / nds32-isr.c
1 /* Subroutines used for ISR of Andes NDS32 cpu for GNU compiler
2 Copyright (C) 2012-2018 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
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
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
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
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
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
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
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
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
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 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(). */
660 void
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
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
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
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
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 /* ------------------------------------------------------------- */