1 /* Subroutines used for ISR of Andes NDS32 cpu for GNU compiler
2 Copyright (C) 2012-2015 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 /* ------------------------------------------------------------------------ */
25 #include "coretypes.h"
30 #include "stor-layout.h"
35 #include "hard-reg-set.h"
36 #include "insn-config.h" /* Required by recog.h. */
37 #include "conditions.h"
39 #include "insn-attr.h" /* For DFA state_t. */
40 #include "insn-codes.h" /* For CODE_FOR_xxx. */
41 #include "reload.h" /* For push_reload(). */
44 #include "insn-config.h"
52 #include "diagnostic-core.h"
53 #include "dominance.h"
59 #include "cfgcleanup.h"
61 #include "basic-block.h"
64 #include "tm-constrs.h"
65 #include "optabs.h" /* For GEN_FCN. */
67 #include "target-def.h"
68 #include "langhooks.h" /* For add_builtin_function(). */
71 /* ------------------------------------------------------------------------ */
73 /* Refer to nds32.h, there are maximum 73 isr vectors in nds32 architecture.
74 0 for reset handler with __attribute__((reset())),
75 1-8 for exception handler with __attribute__((exception(1,...,8))),
76 and 9-72 for interrupt handler with __attribute__((interrupt(0,...,63))).
77 We use an array to record essential information for each vector. */
78 static struct nds32_isr_info nds32_isr_vectors
[NDS32_N_ISR_VECTORS
];
80 /* ------------------------------------------------------------------------ */
82 /* A helper function to emit section head template. */
84 nds32_emit_section_head_template (char section_name
[],
89 const char *flags_str
;
92 flags_str
= (object_p
) ? "\"a\"" : "\"ax\"";
93 type_str
= (object_p
) ? "@object" : "@function";
95 fprintf (asm_out_file
, "\t.section\t%s, %s\n", section_name
, flags_str
);
96 fprintf (asm_out_file
, "\t.align\t%d\n", align_value
);
97 fprintf (asm_out_file
, "\t.global\t%s\n", symbol_name
);
98 fprintf (asm_out_file
, "\t.type\t%s, %s\n", symbol_name
, type_str
);
99 fprintf (asm_out_file
, "%s:\n", symbol_name
);
102 /* A helper function to emit section tail template. */
104 nds32_emit_section_tail_template (char symbol_name
[])
106 fprintf (asm_out_file
, "\t.size\t%s, .-%s\n", symbol_name
, symbol_name
);
109 /* Function to emit isr jump table section. */
111 nds32_emit_isr_jmptbl_section (int vector_id
)
113 char section_name
[100];
114 char symbol_name
[100];
116 /* Prepare jmptbl section and symbol name. */
117 snprintf (section_name
, sizeof (section_name
),
118 ".nds32_jmptbl.%02d", vector_id
);
119 snprintf (symbol_name
, sizeof (symbol_name
),
120 "_nds32_jmptbl_%02d", vector_id
);
122 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
123 fprintf (asm_out_file
, "\t.word\t%s\n",
124 nds32_isr_vectors
[vector_id
].func_name
);
125 nds32_emit_section_tail_template (symbol_name
);
128 /* Function to emit isr vector section. */
130 nds32_emit_isr_vector_section (int vector_id
)
132 unsigned int vector_number_offset
= 0;
133 const char *c_str
= "CATEGORY";
134 const char *sr_str
= "SR";
135 const char *nt_str
= "NT";
136 const char *vs_str
= "VS";
137 char first_level_handler_name
[100];
138 char section_name
[100];
139 char symbol_name
[100];
141 /* Set the vector number offset so that we can calculate
142 the value that user specifies in the attribute.
143 We also prepare the category string for first level handler name. */
144 switch (nds32_isr_vectors
[vector_id
].category
)
146 case NDS32_ISR_INTERRUPT
:
147 vector_number_offset
= 9;
150 case NDS32_ISR_EXCEPTION
:
151 vector_number_offset
= 0;
155 case NDS32_ISR_RESET
:
156 /* Normally it should not be here. */
161 /* Prepare save reg string for first level handler name. */
162 switch (nds32_isr_vectors
[vector_id
].save_reg
)
167 case NDS32_PARTIAL_SAVE
:
172 /* Prepare nested type string for first level handler name. */
173 switch (nds32_isr_vectors
[vector_id
].nested_type
)
178 case NDS32_NOT_NESTED
:
181 case NDS32_NESTED_READY
:
186 /* Currently we have 4-byte or 16-byte size for each vector.
187 If it is 4-byte, the first level handler name has suffix string "_4b". */
188 vs_str
= (nds32_isr_vector_size
== 4) ? "_4b" : "";
190 /* Now we can create first level handler name. */
191 snprintf (first_level_handler_name
, sizeof (first_level_handler_name
),
192 "_nds32_%s_%s_%s%s", c_str
, sr_str
, nt_str
, vs_str
);
194 /* Prepare vector section and symbol name. */
195 snprintf (section_name
, sizeof (section_name
),
196 ".nds32_vector.%02d", vector_id
);
197 snprintf (symbol_name
, sizeof (symbol_name
),
198 "_nds32_vector_%02d%s", vector_id
, vs_str
);
201 /* Everything is ready. We can start emit vector section content. */
202 nds32_emit_section_head_template (section_name
, symbol_name
,
203 floor_log2 (nds32_isr_vector_size
), false);
205 /* According to the vector size, the instructions in the
206 vector section may be different. */
207 if (nds32_isr_vector_size
== 4)
209 /* This block is for 4-byte vector size.
210 Hardware $VID support is necessary and only one instruction
211 is needed in vector section. */
212 fprintf (asm_out_file
, "\tj\t%s ! jump to first level handler\n",
213 first_level_handler_name
);
217 /* This block is for 16-byte vector size.
218 There is NO hardware $VID so that we need several instructions
219 such as pushing GPRs and preparing software vid at vector section.
220 For pushing GPRs, there are four variations for
221 16-byte vector content and we have to handle each combination.
222 For preparing software vid, note that the vid need to
223 be substracted vector_number_offset. */
224 if (TARGET_REDUCED_REGS
)
226 if (nds32_isr_vectors
[vector_id
].save_reg
== NDS32_SAVE_ALL
)
228 /* Case of reduced set registers and save_all attribute. */
229 fprintf (asm_out_file
, "\t! reduced set regs + save_all\n");
230 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r15, 0xf\n");
231 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r10, 0x0\n");
236 /* Case of reduced set registers and partial_save attribute. */
237 fprintf (asm_out_file
, "\t! reduced set regs + partial_save\n");
238 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r15, 0x2\n");
239 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
244 if (nds32_isr_vectors
[vector_id
].save_reg
== NDS32_SAVE_ALL
)
246 /* Case of full set registers and save_all attribute. */
247 fprintf (asm_out_file
, "\t! full set regs + save_all\n");
248 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r27, 0xf\n");
252 /* Case of full set registers and partial_save attribute. */
253 fprintf (asm_out_file
, "\t! full set regs + partial_save\n");
254 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r27, 0x2\n");
255 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
259 fprintf (asm_out_file
, "\tmovi\t$r0, %d ! preparing software vid\n",
260 vector_id
- vector_number_offset
);
261 fprintf (asm_out_file
, "\tj\t%s ! jump to first level handler\n",
262 first_level_handler_name
);
265 nds32_emit_section_tail_template (symbol_name
);
268 /* Function to emit isr reset handler content.
269 Including all jmptbl/vector references, jmptbl section,
270 vector section, nmi handler section, and warm handler section. */
272 nds32_emit_isr_reset_content (void)
275 unsigned int total_n_vectors
;
277 char reset_handler_name
[100];
278 char section_name
[100];
279 char symbol_name
[100];
281 total_n_vectors
= nds32_isr_vectors
[0].total_n_vectors
;
282 vs_str
= (nds32_isr_vector_size
== 4) ? "_4b" : "";
284 fprintf (asm_out_file
, "\t! RESET HANDLER CONTENT - BEGIN !\n");
286 /* Create references in .rodata according to total number of vectors. */
287 fprintf (asm_out_file
, "\t.section\t.rodata\n");
288 fprintf (asm_out_file
, "\t.align\t2\n");
290 /* Emit jmptbl references. */
291 fprintf (asm_out_file
, "\t ! references to jmptbl section entries\n");
292 for (i
= 0; i
< total_n_vectors
; i
++)
293 fprintf (asm_out_file
, "\t.word\t_nds32_jmptbl_%02d\n", i
);
295 /* Emit vector references. */
296 fprintf (asm_out_file
, "\t ! references to vector section entries\n");
297 for (i
= 0; i
< total_n_vectors
; i
++)
298 fprintf (asm_out_file
, "\t.word\t_nds32_vector_%02d%s\n", i
, vs_str
);
300 /* Emit jmptbl_00 section. */
301 snprintf (section_name
, sizeof (section_name
), ".nds32_jmptbl.00");
302 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_jmptbl_00");
304 fprintf (asm_out_file
, "\t! ....................................\n");
305 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
306 fprintf (asm_out_file
, "\t.word\t%s\n",
307 nds32_isr_vectors
[0].func_name
);
308 nds32_emit_section_tail_template (symbol_name
);
310 /* Emit vector_00 section. */
311 snprintf (section_name
, sizeof (section_name
), ".nds32_vector.00");
312 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_vector_00%s", vs_str
);
313 snprintf (reset_handler_name
, sizeof (reset_handler_name
),
314 "_nds32_reset%s", vs_str
);
316 fprintf (asm_out_file
, "\t! ....................................\n");
317 nds32_emit_section_head_template (section_name
, symbol_name
,
318 floor_log2 (nds32_isr_vector_size
), false);
319 fprintf (asm_out_file
, "\tj\t%s ! jump to reset handler\n",
321 nds32_emit_section_tail_template (symbol_name
);
323 /* Emit nmi handler section. */
324 snprintf (section_name
, sizeof (section_name
), ".nds32_nmih");
325 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_nmih");
327 fprintf (asm_out_file
, "\t! ....................................\n");
328 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
329 fprintf (asm_out_file
, "\t.word\t%s\n",
330 (strlen (nds32_isr_vectors
[0].nmi_name
) == 0)
332 : nds32_isr_vectors
[0].nmi_name
);
333 nds32_emit_section_tail_template (symbol_name
);
335 /* Emit warm handler section. */
336 snprintf (section_name
, sizeof (section_name
), ".nds32_wrh");
337 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_wrh");
339 fprintf (asm_out_file
, "\t! ....................................\n");
340 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
341 fprintf (asm_out_file
, "\t.word\t%s\n",
342 (strlen (nds32_isr_vectors
[0].warm_name
) == 0)
344 : nds32_isr_vectors
[0].warm_name
);
345 nds32_emit_section_tail_template (symbol_name
);
347 fprintf (asm_out_file
, "\t! RESET HANDLER CONTENT - END !\n");
350 /* Function for nds32_merge_decl_attributes() and nds32_insert_attributes()
351 to check if there are any conflict isr-specific attributes being set.
353 1. Only 'save_all' or 'partial_save' in the attributes.
354 2. Only 'nested', 'not_nested', or 'nested_ready' in the attributes.
355 3. Only 'interrupt', 'exception', or 'reset' in the attributes. */
357 nds32_check_isr_attrs_conflict (tree func_decl
, tree func_attrs
)
359 int save_all_p
, partial_save_p
;
360 int nested_p
, not_nested_p
, nested_ready_p
;
361 int intr_p
, excp_p
, reset_p
;
363 /* Initialize variables. */
364 save_all_p
= partial_save_p
= 0;
365 nested_p
= not_nested_p
= nested_ready_p
= 0;
366 intr_p
= excp_p
= reset_p
= 0;
368 /* We must check at MOST one attribute to set save-reg. */
369 if (lookup_attribute ("save_all", func_attrs
))
371 if (lookup_attribute ("partial_save", func_attrs
))
374 if ((save_all_p
+ partial_save_p
) > 1)
375 error ("multiple save reg attributes to function %qD", func_decl
);
377 /* We must check at MOST one attribute to set nested-type. */
378 if (lookup_attribute ("nested", func_attrs
))
380 if (lookup_attribute ("not_nested", func_attrs
))
382 if (lookup_attribute ("nested_ready", func_attrs
))
385 if ((nested_p
+ not_nested_p
+ nested_ready_p
) > 1)
386 error ("multiple nested types attributes to function %qD", func_decl
);
388 /* We must check at MOST one attribute to
389 set interrupt/exception/reset. */
390 if (lookup_attribute ("interrupt", func_attrs
))
392 if (lookup_attribute ("exception", func_attrs
))
394 if (lookup_attribute ("reset", func_attrs
))
397 if ((intr_p
+ excp_p
+ reset_p
) > 1)
398 error ("multiple interrupt attributes to function %qD", func_decl
);
401 /* Function to construct isr vectors information array.
402 We DO NOT HAVE TO check if the attributes are valid
403 because those works are supposed to be done on
404 nds32_merge_decl_attributes() and nds32_insert_attributes(). */
406 nds32_construct_isr_vectors_information (tree func_attrs
,
407 const char *func_name
)
409 tree save_all
, partial_save
;
410 tree nested
, not_nested
, nested_ready
;
411 tree intr
, excp
, reset
;
413 save_all
= lookup_attribute ("save_all", func_attrs
);
414 partial_save
= lookup_attribute ("partial_save", func_attrs
);
416 nested
= lookup_attribute ("nested", func_attrs
);
417 not_nested
= lookup_attribute ("not_nested", func_attrs
);
418 nested_ready
= lookup_attribute ("nested_ready", func_attrs
);
420 intr
= lookup_attribute ("interrupt", func_attrs
);
421 excp
= lookup_attribute ("exception", func_attrs
);
422 reset
= lookup_attribute ("reset", func_attrs
);
424 /* If there is no interrupt/exception/reset, we can return immediately. */
425 if (!intr
&& !excp
&& !reset
)
428 /* If we are here, either we have interrupt/exception,
429 or reset attribute. */
434 /* Prepare id list so that we can traverse and set vector id. */
435 id_list
= (intr
) ? (TREE_VALUE (intr
)) : (TREE_VALUE (excp
));
441 unsigned int vector_number_offset
;
443 /* The way to handle interrupt or exception is the same,
444 we just need to take care of actual vector number.
445 For interrupt(0..63), the actual vector number is (9..72).
446 For exception(1..8), the actual vector number is (1..8). */
447 vector_number_offset
= (intr
) ? (9) : (0);
449 /* Pick up each vector id value. */
450 id
= TREE_VALUE (id_list
);
451 /* Add vector_number_offset to get actual vector number. */
452 vector_id
= TREE_INT_CST_LOW (id
) + vector_number_offset
;
454 /* Enable corresponding vector and set function name. */
455 nds32_isr_vectors
[vector_id
].category
= (intr
)
456 ? (NDS32_ISR_INTERRUPT
)
457 : (NDS32_ISR_EXCEPTION
);
458 strcpy (nds32_isr_vectors
[vector_id
].func_name
, func_name
);
460 /* Set register saving scheme. */
462 nds32_isr_vectors
[vector_id
].save_reg
= NDS32_SAVE_ALL
;
463 else if (partial_save
)
464 nds32_isr_vectors
[vector_id
].save_reg
= NDS32_PARTIAL_SAVE
;
466 /* Set nested type. */
468 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NESTED
;
470 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NOT_NESTED
;
471 else if (nested_ready
)
472 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NESTED_READY
;
474 /* Advance to next id. */
475 id_list
= TREE_CHAIN (id_list
);
484 /* Deal with reset attribute. Its vector number is always 0. */
485 nds32_isr_vectors
[0].category
= NDS32_ISR_RESET
;
487 /* Prepare id_list and identify id value so that
488 we can set total number of vectors. */
489 id_list
= TREE_VALUE (reset
);
490 id
= TREE_VALUE (id_list
);
492 /* The total vectors = interrupt + exception numbers + reset.
493 There are 8 exception and 1 reset in nds32 architecture. */
494 nds32_isr_vectors
[0].total_n_vectors
= TREE_INT_CST_LOW (id
) + 8 + 1;
495 strcpy (nds32_isr_vectors
[0].func_name
, func_name
);
497 /* Retrieve nmi and warm function. */
498 nmi
= lookup_attribute ("nmi", func_attrs
);
499 warm
= lookup_attribute ("warm", func_attrs
);
501 if (nmi
!= NULL_TREE
)
506 nmi_func_list
= TREE_VALUE (nmi
);
507 nmi_func
= TREE_VALUE (nmi_func_list
);
509 /* Record nmi function name. */
510 strcpy (nds32_isr_vectors
[0].nmi_name
,
511 IDENTIFIER_POINTER (nmi_func
));
514 if (warm
!= NULL_TREE
)
519 warm_func_list
= TREE_VALUE (warm
);
520 warm_func
= TREE_VALUE (warm_func_list
);
522 /* Record warm function name. */
523 strcpy (nds32_isr_vectors
[0].warm_name
,
524 IDENTIFIER_POINTER (warm_func
));
529 /* A helper function to handle isr stuff at the beginning of asm file. */
531 nds32_asm_file_start_for_isr (void)
535 /* Initialize isr vector information array before compiling functions. */
536 for (i
= 0; i
< NDS32_N_ISR_VECTORS
; i
++)
538 nds32_isr_vectors
[i
].category
= NDS32_ISR_NONE
;
539 strcpy (nds32_isr_vectors
[i
].func_name
, "");
540 nds32_isr_vectors
[i
].save_reg
= NDS32_PARTIAL_SAVE
;
541 nds32_isr_vectors
[i
].nested_type
= NDS32_NOT_NESTED
;
542 nds32_isr_vectors
[i
].total_n_vectors
= 0;
543 strcpy (nds32_isr_vectors
[i
].nmi_name
, "");
544 strcpy (nds32_isr_vectors
[i
].warm_name
, "");
548 /* A helper function to handle isr stuff at the end of asm file. */
550 nds32_asm_file_end_for_isr (void)
554 /* If all the vectors are NDS32_ISR_NONE, we can return immediately. */
555 for (i
= 0; i
< NDS32_N_ISR_VECTORS
; i
++)
556 if (nds32_isr_vectors
[i
].category
!= NDS32_ISR_NONE
)
559 if (i
== NDS32_N_ISR_VECTORS
)
562 /* At least one vector is NOT NDS32_ISR_NONE,
563 we should output isr vector information. */
564 fprintf (asm_out_file
, "\t! ------------------------------------\n");
565 fprintf (asm_out_file
, "\t! The isr vector information:\n");
566 fprintf (asm_out_file
, "\t! ------------------------------------\n");
568 /* Check reset handler first. Its vector number is always 0. */
569 if (nds32_isr_vectors
[0].category
== NDS32_ISR_RESET
)
571 nds32_emit_isr_reset_content ();
572 fprintf (asm_out_file
, "\t! ------------------------------------\n");
575 /* Check other vectors, starting from vector number 1. */
576 for (i
= 1; i
< NDS32_N_ISR_VECTORS
; i
++)
578 if (nds32_isr_vectors
[i
].category
== NDS32_ISR_INTERRUPT
579 || nds32_isr_vectors
[i
].category
== NDS32_ISR_EXCEPTION
)
581 /* Found one vector which is interupt or exception.
582 Output its jmptbl and vector section content. */
583 fprintf (asm_out_file
, "\t! interrupt/exception vector %02d\n", i
);
584 fprintf (asm_out_file
, "\t! ------------------------------------\n");
585 nds32_emit_isr_jmptbl_section (i
);
586 fprintf (asm_out_file
, "\t! ....................................\n");
587 nds32_emit_isr_vector_section (i
);
588 fprintf (asm_out_file
, "\t! ------------------------------------\n");
593 /* Return true if FUNC is a isr function. */
595 nds32_isr_function_p (tree func
)
603 if (TREE_CODE (func
) != FUNCTION_DECL
)
606 attrs
= DECL_ATTRIBUTES (func
);
608 t_intr
= lookup_attribute ("interrupt", attrs
);
609 t_excp
= lookup_attribute ("exception", attrs
);
610 t_reset
= lookup_attribute ("reset", attrs
);
612 return ((t_intr
!= NULL_TREE
)
613 || (t_excp
!= NULL_TREE
)
614 || (t_reset
!= NULL_TREE
));
617 /* ------------------------------------------------------------------------ */