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.
5 This file is part of GCC.
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.
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.
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/>. */
21 /* ------------------------------------------------------------------------ */
23 #define IN_TARGET_CODE 1
27 #include "coretypes.h"
32 #include "stringpool.h"
34 #include "diagnostic-core.h"
37 /* ------------------------------------------------------------------------ */
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
];
46 /* ------------------------------------------------------------- */
48 FOR BACKWARD COMPATIBILITY, we need to support following patterns:
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")))
54 We provide several functions to parse the strings. */
57 nds32_interrupt_attribute_parse_string (const char *original_str
,
58 const char *func_name
,
62 enum nds32_isr_save_reg save_reg
;
63 enum nds32_isr_nested_type nested_type
;
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
;
69 /* Copy original string into a character array so that
70 the string APIs can handle it. */
71 strcpy (target_str
, original_str
);
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");
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
;
85 save_reg
= NDS32_PARTIAL_SAVE
;
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");
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. */
101 nested_type
= NDS32_NOT_NESTED
;
102 else if (ready_nested_str
)
103 nested_type
= NDS32_NESTED_READY
;
105 nested_type
= NDS32_NESTED
;
106 else if (critical_str
)
107 nested_type
= NDS32_CRITICAL
;
109 nested_type
= NDS32_NOT_NESTED
;
111 /* 3. Traverse each id value and set corresponding information. */
112 id_str
= strstr (target_str
, "id=");
114 /* If user forgets to assign 'id', issue an error message. */
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
, ";");
121 /* Pick up the first id value token. */
122 value_str
= strtok (value_str
, ",");
123 while (value_str
!= NULL
)
126 i
= atoi (value_str
);
128 /* For interrupt(0..63), the actual vector number is (9..72). */
131 error ("invalid id value for interrupt attribute");
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
;
140 /* Fetch next token. */
141 value_str
= strtok (NULL
, ",");
148 nds32_exception_attribute_parse_string (const char *original_str
,
149 const char *func_name
,
150 unsigned int s_level
)
152 char target_str
[100];
153 enum nds32_isr_save_reg save_reg
;
154 enum nds32_isr_nested_type nested_type
;
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
;
160 /* Copy original string into a character array so that
161 the string APIs can handle it. */
162 strcpy (target_str
, original_str
);
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");
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
;
176 save_reg
= NDS32_PARTIAL_SAVE
;
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");
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. */
192 nested_type
= NDS32_NOT_NESTED
;
193 else if (ready_nested_str
)
194 nested_type
= NDS32_NESTED_READY
;
196 nested_type
= NDS32_NESTED
;
197 else if (critical_str
)
198 nested_type
= NDS32_CRITICAL
;
200 nested_type
= NDS32_NOT_NESTED
;
202 /* 3. Traverse each id value and set corresponding information. */
203 id_str
= strstr (target_str
, "id=");
205 /* If user forgets to assign 'id', issue an error message. */
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
, ";");
212 /* Pick up the first id value token. */
213 value_str
= strtok (value_str
, ",");
214 while (value_str
!= NULL
)
217 i
= atoi (value_str
);
219 /* For exception(1..8), the actual vector number is (1..8). */
221 error ("invalid id value for exception attribute");
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
;
230 /* Fetch next token. */
231 value_str
= strtok (NULL
, ",");
238 nds32_reset_attribute_parse_string (const char *original_str
,
239 const char *func_name
)
241 char target_str
[100];
242 char *vectors_str
, *nmi_str
, *warm_str
, *value_str
;
244 /* Deal with reset attribute. Its vector number is always 0. */
245 nds32_isr_vectors
[0].category
= NDS32_ISR_RESET
;
248 /* 1. Parse 'vectors=XXXX'. */
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
)
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;
265 nds32_isr_vectors
[0].total_n_vectors
= 16 + 8 + 1;
266 strcpy (nds32_isr_vectors
[0].func_name
, func_name
);
269 /* 2. Parse 'nmi_func=YYYY'. */
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=");
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
);
283 /* 3. Parse 'warm_func=ZZZZ'. */
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
)
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
);
299 /* ------------------------------------------------------------- */
301 /* A helper function to emit section head template. */
303 nds32_emit_section_head_template (char section_name
[],
308 const char *flags_str
;
309 const char *type_str
;
311 flags_str
= (object_p
) ? "\"a\"" : "\"ax\"";
312 type_str
= (object_p
) ? "@object" : "@function";
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
);
321 /* A helper function to emit section tail template. */
323 nds32_emit_section_tail_template (char symbol_name
[])
325 fprintf (asm_out_file
, "\t.size\t%s, .-%s\n", symbol_name
, symbol_name
);
328 /* Function to emit isr jump table section. */
330 nds32_emit_isr_jmptbl_section (int vector_id
)
332 char section_name
[100];
333 char symbol_name
[100];
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
)
339 fprintf (asm_out_file
, "\t! The vector %02d is a critical isr !\n",
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
);
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
);
356 /* Function to emit isr vector section. */
358 nds32_emit_isr_vector_section (int vector_id
)
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];
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
)
373 case NDS32_ISR_INTERRUPT
:
374 vector_number_offset
= 9;
377 case NDS32_ISR_EXCEPTION
:
378 vector_number_offset
= 0;
382 case NDS32_ISR_RESET
:
383 /* Normally it should not be here. */
388 /* Prepare save reg string for first level handler name. */
389 switch (nds32_isr_vectors
[vector_id
].save_reg
)
394 case NDS32_PARTIAL_SAVE
:
399 /* Prepare nested type string for first level handler name. */
400 switch (nds32_isr_vectors
[vector_id
].nested_type
)
405 case NDS32_NOT_NESTED
:
408 case NDS32_NESTED_READY
:
412 /* The critical isr is not performed by two-level handler. */
417 /* Now we can create first level handler name. */
418 if (nds32_isr_vectors
[vector_id
].security_level
== 0)
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
);
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
);
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
);
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);
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
)
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
);
451 else if (nds32_isr_vector_size
== 4)
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
);
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
)
470 if (nds32_isr_vectors
[vector_id
].save_reg
== NDS32_SAVE_ALL
)
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");
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");
488 if (nds32_isr_vectors
[vector_id
].save_reg
== NDS32_SAVE_ALL
)
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");
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");
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
);
509 nds32_emit_section_tail_template (symbol_name
);
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. */
516 nds32_emit_isr_reset_content (void)
519 unsigned int total_n_vectors
;
520 char reset_handler_name
[100];
521 char section_name
[100];
522 char symbol_name
[100];
524 total_n_vectors
= nds32_isr_vectors
[0].total_n_vectors
;
526 fprintf (asm_out_file
, "\t! RESET HANDLER CONTENT - BEGIN !\n");
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");
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
);
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
);
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");
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
);
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
),
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",
563 nds32_emit_section_tail_template (symbol_name
);
565 /* Emit nmi handler section. */
566 snprintf (section_name
, sizeof (section_name
), ".nds32_nmih");
567 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_nmih");
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)
574 : nds32_isr_vectors
[0].nmi_name
);
575 nds32_emit_section_tail_template (symbol_name
);
577 /* Emit warm handler section. */
578 snprintf (section_name
, sizeof (section_name
), ".nds32_wrh");
579 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_wrh");
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)
586 : nds32_isr_vectors
[0].warm_name
);
587 nds32_emit_section_tail_template (symbol_name
);
589 fprintf (asm_out_file
, "\t! RESET HANDLER CONTENT - END !\n");
592 /* Function for nds32_merge_decl_attributes() and nds32_insert_attributes()
593 to check if there are any conflict isr-specific attributes being set.
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. */
599 nds32_check_isr_attrs_conflict (tree func_decl
, tree func_attrs
)
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
;
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;
610 /* We must check at MOST one attribute to set save-reg. */
611 if (lookup_attribute ("save_all", func_attrs
))
613 if (lookup_attribute ("partial_save", func_attrs
))
616 if ((save_all_p
+ partial_save_p
) > 1)
617 error ("multiple save reg attributes to function %qD", func_decl
);
619 /* We must check at MOST one attribute to set nested-type. */
620 if (lookup_attribute ("nested", func_attrs
))
622 if (lookup_attribute ("not_nested", func_attrs
))
624 if (lookup_attribute ("nested_ready", func_attrs
))
626 if (lookup_attribute ("critical", func_attrs
))
629 if ((nested_p
+ not_nested_p
+ nested_ready_p
+ critical_p
) > 1)
630 error ("multiple nested types attributes to function %qD", func_decl
);
632 /* We must check at MOST one attribute to
633 set interrupt/exception/reset. */
634 if (lookup_attribute ("interrupt", func_attrs
))
636 if (lookup_attribute ("exception", func_attrs
))
638 if (lookup_attribute ("reset", func_attrs
))
641 if ((intr_p
+ excp_p
+ reset_p
) > 1)
642 error ("multiple interrupt attributes to function %qD", func_decl
);
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
);
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(). */
661 nds32_construct_isr_vectors_information (tree func_attrs
,
662 const char *func_name
)
664 tree save_all
, partial_save
;
665 tree nested
, not_nested
, nested_ready
, critical
;
666 tree intr
, excp
, reset
;
669 tree security_level_list
;
671 unsigned int s_level
;
673 save_all
= lookup_attribute ("save_all", func_attrs
);
674 partial_save
= lookup_attribute ("partial_save", func_attrs
);
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
);
681 intr
= lookup_attribute ("interrupt", func_attrs
);
682 excp
= lookup_attribute ("exception", func_attrs
);
683 reset
= lookup_attribute ("reset", func_attrs
);
685 /* If there is no interrupt/exception/reset, we can return immediately. */
686 if (!intr
&& !excp
&& !reset
)
689 /* At first, we need to retrieve security level. */
690 secure
= lookup_attribute ("secure", func_attrs
);
693 security_level_list
= TREE_VALUE (secure
);
694 security_level
= TREE_VALUE (security_level_list
);
695 s_level
= TREE_INT_CST_LOW (security_level
);
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
;
705 /* ------------------------------------------------------------- */
707 FOR BACKWARD COMPATIBILITY, we need to support following patterns:
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")))
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
)
721 tree string_arg
= TREE_VALUE (TREE_VALUE (intr
));
722 nds32_interrupt_attribute_parse_string (TREE_STRING_POINTER (string_arg
),
727 if (excp
!= NULL_TREE
728 && TREE_CODE (TREE_VALUE (TREE_VALUE (excp
))) == STRING_CST
)
730 tree string_arg
= TREE_VALUE (TREE_VALUE (excp
));
731 nds32_exception_attribute_parse_string (TREE_STRING_POINTER (string_arg
),
736 if (reset
!= NULL_TREE
737 && TREE_CODE (TREE_VALUE (TREE_VALUE (reset
))) == STRING_CST
)
739 tree string_arg
= TREE_VALUE (TREE_VALUE (reset
));
740 nds32_reset_attribute_parse_string (TREE_STRING_POINTER (string_arg
),
744 /* ------------------------------------------------------------- */
746 /* If we are here, either we have interrupt/exception,
747 or reset attribute. */
752 /* Prepare id list so that we can traverse and set vector id. */
753 id_list
= (intr
) ? (TREE_VALUE (intr
)) : (TREE_VALUE (excp
));
759 unsigned int vector_number_offset
;
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);
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
;
772 /* Set security level. */
773 nds32_isr_vectors
[vector_id
].security_level
= s_level
;
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
);
781 /* Set register saving scheme. */
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
;
787 /* Set nested type. */
789 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_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
;
795 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_CRITICAL
;
797 /* Advance to next id. */
798 id_list
= TREE_CHAIN (id_list
);
807 /* Deal with reset attribute. Its vector number is always 0. */
808 nds32_isr_vectors
[0].category
= NDS32_ISR_RESET
;
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
);
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
);
820 /* Retrieve nmi and warm function. */
821 nmi
= lookup_attribute ("nmi", func_attrs
);
822 warm
= lookup_attribute ("warm", func_attrs
);
824 if (nmi
!= NULL_TREE
)
829 nmi_func_list
= TREE_VALUE (nmi
);
830 nmi_func
= TREE_VALUE (nmi_func_list
);
832 /* Record nmi function name. */
833 strcpy (nds32_isr_vectors
[0].nmi_name
,
834 IDENTIFIER_POINTER (nmi_func
));
837 if (warm
!= NULL_TREE
)
842 warm_func_list
= TREE_VALUE (warm
);
843 warm_func
= TREE_VALUE (warm_func_list
);
845 /* Record warm function name. */
846 strcpy (nds32_isr_vectors
[0].warm_name
,
847 IDENTIFIER_POINTER (warm_func
));
853 nds32_asm_file_start_for_isr (void)
857 /* Initialize isr vector information array before compiling functions. */
858 for (i
= 0; i
< NDS32_N_ISR_VECTORS
; i
++)
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
, "");
871 void nds32_asm_file_end_for_isr (void)
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
)
880 if (i
== NDS32_N_ISR_VECTORS
)
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");
889 /* Check reset handler first. Its vector number is always 0. */
890 if (nds32_isr_vectors
[0].category
== NDS32_ISR_RESET
)
892 nds32_emit_isr_reset_content ();
893 fprintf (asm_out_file
, "\t! ------------------------------------\n");
896 /* Check other vectors, starting from vector number 1. */
897 for (i
= 1; i
< NDS32_N_ISR_VECTORS
; i
++)
899 if (nds32_isr_vectors
[i
].category
== NDS32_ISR_INTERRUPT
900 || nds32_isr_vectors
[i
].category
== NDS32_ISR_EXCEPTION
)
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");
916 /* Return true if FUNC is a isr function. */
918 nds32_isr_function_p (tree func
)
926 if (TREE_CODE (func
) != FUNCTION_DECL
)
929 attrs
= DECL_ATTRIBUTES (func
);
931 t_intr
= lookup_attribute ("interrupt", attrs
);
932 t_excp
= lookup_attribute ("exception", attrs
);
933 t_reset
= lookup_attribute ("reset", attrs
);
935 return ((t_intr
!= NULL_TREE
)
936 || (t_excp
!= NULL_TREE
)
937 || (t_reset
!= NULL_TREE
));
940 /* Return true if FUNC is a isr function with critical attribute. */
942 nds32_isr_function_critical_p (tree func
)
950 if (TREE_CODE (func
) != FUNCTION_DECL
)
953 attrs
= DECL_ATTRIBUTES (func
);
955 t_intr
= lookup_attribute ("interrupt", attrs
);
956 t_excp
= lookup_attribute ("exception", attrs
);
958 t_critical
= lookup_attribute ("critical", attrs
);
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
))
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
)
971 /* ------------------------------------------------------------- */
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
)
978 char target_str
[100];
983 t_check
= t_intr
? t_intr
: t_excp
;
984 if (TREE_CODE (TREE_VALUE (TREE_VALUE (t_check
))) == STRING_CST
)
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");
990 /* Found 'critical' string, so return true. */
995 /* ------------------------------------------------------------- */
997 /* Other cases, this isr function is not critical type. */
1001 /* ------------------------------------------------------------- */