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 "double-int.h"
37 #include "stor-layout.h"
42 #include "hard-reg-set.h"
43 #include "insn-config.h" /* Required by recog.h. */
44 #include "conditions.h"
46 #include "insn-attr.h" /* For DFA state_t. */
47 #include "insn-codes.h" /* For CODE_FOR_xxx. */
48 #include "reload.h" /* For push_reload(). */
52 #include "statistics.h"
54 #include "fixed-value.h"
55 #include "insn-config.h"
63 #include "diagnostic-core.h"
64 #include "dominance.h"
70 #include "cfgcleanup.h"
72 #include "basic-block.h"
75 #include "tm-constrs.h"
76 #include "optabs.h" /* For GEN_FCN. */
78 #include "target-def.h"
79 #include "langhooks.h" /* For add_builtin_function(). */
83 /* ------------------------------------------------------------------------ */
85 /* Refer to nds32.h, there are maximum 73 isr vectors in nds32 architecture.
86 0 for reset handler with __attribute__((reset())),
87 1-8 for exception handler with __attribute__((exception(1,...,8))),
88 and 9-72 for interrupt handler with __attribute__((interrupt(0,...,63))).
89 We use an array to record essential information for each vector. */
90 static struct nds32_isr_info nds32_isr_vectors
[NDS32_N_ISR_VECTORS
];
92 /* ------------------------------------------------------------------------ */
94 /* A helper function to emit section head template. */
96 nds32_emit_section_head_template (char section_name
[],
101 const char *flags_str
;
102 const char *type_str
;
104 flags_str
= (object_p
) ? "\"a\"" : "\"ax\"";
105 type_str
= (object_p
) ? "@object" : "@function";
107 fprintf (asm_out_file
, "\t.section\t%s, %s\n", section_name
, flags_str
);
108 fprintf (asm_out_file
, "\t.align\t%d\n", align_value
);
109 fprintf (asm_out_file
, "\t.global\t%s\n", symbol_name
);
110 fprintf (asm_out_file
, "\t.type\t%s, %s\n", symbol_name
, type_str
);
111 fprintf (asm_out_file
, "%s:\n", symbol_name
);
114 /* A helper function to emit section tail template. */
116 nds32_emit_section_tail_template (char symbol_name
[])
118 fprintf (asm_out_file
, "\t.size\t%s, .-%s\n", symbol_name
, symbol_name
);
121 /* Function to emit isr jump table section. */
123 nds32_emit_isr_jmptbl_section (int vector_id
)
125 char section_name
[100];
126 char symbol_name
[100];
128 /* Prepare jmptbl section and symbol name. */
129 snprintf (section_name
, sizeof (section_name
),
130 ".nds32_jmptbl.%02d", vector_id
);
131 snprintf (symbol_name
, sizeof (symbol_name
),
132 "_nds32_jmptbl_%02d", vector_id
);
134 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
135 fprintf (asm_out_file
, "\t.word\t%s\n",
136 nds32_isr_vectors
[vector_id
].func_name
);
137 nds32_emit_section_tail_template (symbol_name
);
140 /* Function to emit isr vector section. */
142 nds32_emit_isr_vector_section (int vector_id
)
144 unsigned int vector_number_offset
= 0;
145 const char *c_str
= "CATEGORY";
146 const char *sr_str
= "SR";
147 const char *nt_str
= "NT";
148 const char *vs_str
= "VS";
149 char first_level_handler_name
[100];
150 char section_name
[100];
151 char symbol_name
[100];
153 /* Set the vector number offset so that we can calculate
154 the value that user specifies in the attribute.
155 We also prepare the category string for first level handler name. */
156 switch (nds32_isr_vectors
[vector_id
].category
)
158 case NDS32_ISR_INTERRUPT
:
159 vector_number_offset
= 9;
162 case NDS32_ISR_EXCEPTION
:
163 vector_number_offset
= 0;
167 case NDS32_ISR_RESET
:
168 /* Normally it should not be here. */
173 /* Prepare save reg string for first level handler name. */
174 switch (nds32_isr_vectors
[vector_id
].save_reg
)
179 case NDS32_PARTIAL_SAVE
:
184 /* Prepare nested type string for first level handler name. */
185 switch (nds32_isr_vectors
[vector_id
].nested_type
)
190 case NDS32_NOT_NESTED
:
193 case NDS32_NESTED_READY
:
198 /* Currently we have 4-byte or 16-byte size for each vector.
199 If it is 4-byte, the first level handler name has suffix string "_4b". */
200 vs_str
= (nds32_isr_vector_size
== 4) ? "_4b" : "";
202 /* Now we can create first level handler name. */
203 snprintf (first_level_handler_name
, sizeof (first_level_handler_name
),
204 "_nds32_%s_%s_%s%s", c_str
, sr_str
, nt_str
, vs_str
);
206 /* Prepare vector section and symbol name. */
207 snprintf (section_name
, sizeof (section_name
),
208 ".nds32_vector.%02d", vector_id
);
209 snprintf (symbol_name
, sizeof (symbol_name
),
210 "_nds32_vector_%02d%s", vector_id
, vs_str
);
213 /* Everything is ready. We can start emit vector section content. */
214 nds32_emit_section_head_template (section_name
, symbol_name
,
215 floor_log2 (nds32_isr_vector_size
), false);
217 /* According to the vector size, the instructions in the
218 vector section may be different. */
219 if (nds32_isr_vector_size
== 4)
221 /* This block is for 4-byte vector size.
222 Hardware $VID support is necessary and only one instruction
223 is needed in vector section. */
224 fprintf (asm_out_file
, "\tj\t%s ! jump to first level handler\n",
225 first_level_handler_name
);
229 /* This block is for 16-byte vector size.
230 There is NO hardware $VID so that we need several instructions
231 such as pushing GPRs and preparing software vid at vector section.
232 For pushing GPRs, there are four variations for
233 16-byte vector content and we have to handle each combination.
234 For preparing software vid, note that the vid need to
235 be substracted vector_number_offset. */
236 if (TARGET_REDUCED_REGS
)
238 if (nds32_isr_vectors
[vector_id
].save_reg
== NDS32_SAVE_ALL
)
240 /* Case of reduced set registers and save_all attribute. */
241 fprintf (asm_out_file
, "\t! reduced set regs + save_all\n");
242 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r15, 0xf\n");
243 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r10, 0x0\n");
248 /* Case of reduced set registers and partial_save attribute. */
249 fprintf (asm_out_file
, "\t! reduced set regs + partial_save\n");
250 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r15, 0x2\n");
251 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
256 if (nds32_isr_vectors
[vector_id
].save_reg
== NDS32_SAVE_ALL
)
258 /* Case of full set registers and save_all attribute. */
259 fprintf (asm_out_file
, "\t! full set regs + save_all\n");
260 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r27, 0xf\n");
264 /* Case of full set registers and partial_save attribute. */
265 fprintf (asm_out_file
, "\t! full set regs + partial_save\n");
266 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r27, 0x2\n");
267 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
271 fprintf (asm_out_file
, "\tmovi\t$r0, %d ! preparing software vid\n",
272 vector_id
- vector_number_offset
);
273 fprintf (asm_out_file
, "\tj\t%s ! jump to first level handler\n",
274 first_level_handler_name
);
277 nds32_emit_section_tail_template (symbol_name
);
280 /* Function to emit isr reset handler content.
281 Including all jmptbl/vector references, jmptbl section,
282 vector section, nmi handler section, and warm handler section. */
284 nds32_emit_isr_reset_content (void)
287 unsigned int total_n_vectors
;
289 char reset_handler_name
[100];
290 char section_name
[100];
291 char symbol_name
[100];
293 total_n_vectors
= nds32_isr_vectors
[0].total_n_vectors
;
294 vs_str
= (nds32_isr_vector_size
== 4) ? "_4b" : "";
296 fprintf (asm_out_file
, "\t! RESET HANDLER CONTENT - BEGIN !\n");
298 /* Create references in .rodata according to total number of vectors. */
299 fprintf (asm_out_file
, "\t.section\t.rodata\n");
300 fprintf (asm_out_file
, "\t.align\t2\n");
302 /* Emit jmptbl references. */
303 fprintf (asm_out_file
, "\t ! references to jmptbl section entries\n");
304 for (i
= 0; i
< total_n_vectors
; i
++)
305 fprintf (asm_out_file
, "\t.word\t_nds32_jmptbl_%02d\n", i
);
307 /* Emit vector references. */
308 fprintf (asm_out_file
, "\t ! references to vector section entries\n");
309 for (i
= 0; i
< total_n_vectors
; i
++)
310 fprintf (asm_out_file
, "\t.word\t_nds32_vector_%02d%s\n", i
, vs_str
);
312 /* Emit jmptbl_00 section. */
313 snprintf (section_name
, sizeof (section_name
), ".nds32_jmptbl.00");
314 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_jmptbl_00");
316 fprintf (asm_out_file
, "\t! ....................................\n");
317 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
318 fprintf (asm_out_file
, "\t.word\t%s\n",
319 nds32_isr_vectors
[0].func_name
);
320 nds32_emit_section_tail_template (symbol_name
);
322 /* Emit vector_00 section. */
323 snprintf (section_name
, sizeof (section_name
), ".nds32_vector.00");
324 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_vector_00%s", vs_str
);
325 snprintf (reset_handler_name
, sizeof (reset_handler_name
),
326 "_nds32_reset%s", vs_str
);
328 fprintf (asm_out_file
, "\t! ....................................\n");
329 nds32_emit_section_head_template (section_name
, symbol_name
,
330 floor_log2 (nds32_isr_vector_size
), false);
331 fprintf (asm_out_file
, "\tj\t%s ! jump to reset handler\n",
333 nds32_emit_section_tail_template (symbol_name
);
335 /* Emit nmi handler section. */
336 snprintf (section_name
, sizeof (section_name
), ".nds32_nmih");
337 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_nmih");
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].nmi_name
) == 0)
344 : nds32_isr_vectors
[0].nmi_name
);
345 nds32_emit_section_tail_template (symbol_name
);
347 /* Emit warm handler section. */
348 snprintf (section_name
, sizeof (section_name
), ".nds32_wrh");
349 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_wrh");
351 fprintf (asm_out_file
, "\t! ....................................\n");
352 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
353 fprintf (asm_out_file
, "\t.word\t%s\n",
354 (strlen (nds32_isr_vectors
[0].warm_name
) == 0)
356 : nds32_isr_vectors
[0].warm_name
);
357 nds32_emit_section_tail_template (symbol_name
);
359 fprintf (asm_out_file
, "\t! RESET HANDLER CONTENT - END !\n");
362 /* Function for nds32_merge_decl_attributes() and nds32_insert_attributes()
363 to check if there are any conflict isr-specific attributes being set.
365 1. Only 'save_all' or 'partial_save' in the attributes.
366 2. Only 'nested', 'not_nested', or 'nested_ready' in the attributes.
367 3. Only 'interrupt', 'exception', or 'reset' in the attributes. */
369 nds32_check_isr_attrs_conflict (tree func_decl
, tree func_attrs
)
371 int save_all_p
, partial_save_p
;
372 int nested_p
, not_nested_p
, nested_ready_p
;
373 int intr_p
, excp_p
, reset_p
;
375 /* Initialize variables. */
376 save_all_p
= partial_save_p
= 0;
377 nested_p
= not_nested_p
= nested_ready_p
= 0;
378 intr_p
= excp_p
= reset_p
= 0;
380 /* We must check at MOST one attribute to set save-reg. */
381 if (lookup_attribute ("save_all", func_attrs
))
383 if (lookup_attribute ("partial_save", func_attrs
))
386 if ((save_all_p
+ partial_save_p
) > 1)
387 error ("multiple save reg attributes to function %qD", func_decl
);
389 /* We must check at MOST one attribute to set nested-type. */
390 if (lookup_attribute ("nested", func_attrs
))
392 if (lookup_attribute ("not_nested", func_attrs
))
394 if (lookup_attribute ("nested_ready", func_attrs
))
397 if ((nested_p
+ not_nested_p
+ nested_ready_p
) > 1)
398 error ("multiple nested types attributes to function %qD", func_decl
);
400 /* We must check at MOST one attribute to
401 set interrupt/exception/reset. */
402 if (lookup_attribute ("interrupt", func_attrs
))
404 if (lookup_attribute ("exception", func_attrs
))
406 if (lookup_attribute ("reset", func_attrs
))
409 if ((intr_p
+ excp_p
+ reset_p
) > 1)
410 error ("multiple interrupt attributes to function %qD", func_decl
);
413 /* Function to construct isr vectors information array.
414 We DO NOT HAVE TO check if the attributes are valid
415 because those works are supposed to be done on
416 nds32_merge_decl_attributes() and nds32_insert_attributes(). */
418 nds32_construct_isr_vectors_information (tree func_attrs
,
419 const char *func_name
)
421 tree save_all
, partial_save
;
422 tree nested
, not_nested
, nested_ready
;
423 tree intr
, excp
, reset
;
425 save_all
= lookup_attribute ("save_all", func_attrs
);
426 partial_save
= lookup_attribute ("partial_save", func_attrs
);
428 nested
= lookup_attribute ("nested", func_attrs
);
429 not_nested
= lookup_attribute ("not_nested", func_attrs
);
430 nested_ready
= lookup_attribute ("nested_ready", func_attrs
);
432 intr
= lookup_attribute ("interrupt", func_attrs
);
433 excp
= lookup_attribute ("exception", func_attrs
);
434 reset
= lookup_attribute ("reset", func_attrs
);
436 /* If there is no interrupt/exception/reset, we can return immediately. */
437 if (!intr
&& !excp
&& !reset
)
440 /* If we are here, either we have interrupt/exception,
441 or reset attribute. */
446 /* Prepare id list so that we can traverse and set vector id. */
447 id_list
= (intr
) ? (TREE_VALUE (intr
)) : (TREE_VALUE (excp
));
453 unsigned int vector_number_offset
;
455 /* The way to handle interrupt or exception is the same,
456 we just need to take care of actual vector number.
457 For interrupt(0..63), the actual vector number is (9..72).
458 For exception(1..8), the actual vector number is (1..8). */
459 vector_number_offset
= (intr
) ? (9) : (0);
461 /* Pick up each vector id value. */
462 id
= TREE_VALUE (id_list
);
463 /* Add vector_number_offset to get actual vector number. */
464 vector_id
= TREE_INT_CST_LOW (id
) + vector_number_offset
;
466 /* Enable corresponding vector and set function name. */
467 nds32_isr_vectors
[vector_id
].category
= (intr
)
468 ? (NDS32_ISR_INTERRUPT
)
469 : (NDS32_ISR_EXCEPTION
);
470 strcpy (nds32_isr_vectors
[vector_id
].func_name
, func_name
);
472 /* Set register saving scheme. */
474 nds32_isr_vectors
[vector_id
].save_reg
= NDS32_SAVE_ALL
;
475 else if (partial_save
)
476 nds32_isr_vectors
[vector_id
].save_reg
= NDS32_PARTIAL_SAVE
;
478 /* Set nested type. */
480 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NESTED
;
482 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NOT_NESTED
;
483 else if (nested_ready
)
484 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NESTED_READY
;
486 /* Advance to next id. */
487 id_list
= TREE_CHAIN (id_list
);
496 /* Deal with reset attribute. Its vector number is always 0. */
497 nds32_isr_vectors
[0].category
= NDS32_ISR_RESET
;
499 /* Prepare id_list and identify id value so that
500 we can set total number of vectors. */
501 id_list
= TREE_VALUE (reset
);
502 id
= TREE_VALUE (id_list
);
504 /* The total vectors = interrupt + exception numbers + reset.
505 There are 8 exception and 1 reset in nds32 architecture. */
506 nds32_isr_vectors
[0].total_n_vectors
= TREE_INT_CST_LOW (id
) + 8 + 1;
507 strcpy (nds32_isr_vectors
[0].func_name
, func_name
);
509 /* Retrieve nmi and warm function. */
510 nmi
= lookup_attribute ("nmi", func_attrs
);
511 warm
= lookup_attribute ("warm", func_attrs
);
513 if (nmi
!= NULL_TREE
)
518 nmi_func_list
= TREE_VALUE (nmi
);
519 nmi_func
= TREE_VALUE (nmi_func_list
);
521 /* Record nmi function name. */
522 strcpy (nds32_isr_vectors
[0].nmi_name
,
523 IDENTIFIER_POINTER (nmi_func
));
526 if (warm
!= NULL_TREE
)
531 warm_func_list
= TREE_VALUE (warm
);
532 warm_func
= TREE_VALUE (warm_func_list
);
534 /* Record warm function name. */
535 strcpy (nds32_isr_vectors
[0].warm_name
,
536 IDENTIFIER_POINTER (warm_func
));
541 /* A helper function to handle isr stuff at the beginning of asm file. */
543 nds32_asm_file_start_for_isr (void)
547 /* Initialize isr vector information array before compiling functions. */
548 for (i
= 0; i
< NDS32_N_ISR_VECTORS
; i
++)
550 nds32_isr_vectors
[i
].category
= NDS32_ISR_NONE
;
551 strcpy (nds32_isr_vectors
[i
].func_name
, "");
552 nds32_isr_vectors
[i
].save_reg
= NDS32_PARTIAL_SAVE
;
553 nds32_isr_vectors
[i
].nested_type
= NDS32_NOT_NESTED
;
554 nds32_isr_vectors
[i
].total_n_vectors
= 0;
555 strcpy (nds32_isr_vectors
[i
].nmi_name
, "");
556 strcpy (nds32_isr_vectors
[i
].warm_name
, "");
560 /* A helper function to handle isr stuff at the end of asm file. */
562 nds32_asm_file_end_for_isr (void)
566 /* If all the vectors are NDS32_ISR_NONE, we can return immediately. */
567 for (i
= 0; i
< NDS32_N_ISR_VECTORS
; i
++)
568 if (nds32_isr_vectors
[i
].category
!= NDS32_ISR_NONE
)
571 if (i
== NDS32_N_ISR_VECTORS
)
574 /* At least one vector is NOT NDS32_ISR_NONE,
575 we should output isr vector information. */
576 fprintf (asm_out_file
, "\t! ------------------------------------\n");
577 fprintf (asm_out_file
, "\t! The isr vector information:\n");
578 fprintf (asm_out_file
, "\t! ------------------------------------\n");
580 /* Check reset handler first. Its vector number is always 0. */
581 if (nds32_isr_vectors
[0].category
== NDS32_ISR_RESET
)
583 nds32_emit_isr_reset_content ();
584 fprintf (asm_out_file
, "\t! ------------------------------------\n");
587 /* Check other vectors, starting from vector number 1. */
588 for (i
= 1; i
< NDS32_N_ISR_VECTORS
; i
++)
590 if (nds32_isr_vectors
[i
].category
== NDS32_ISR_INTERRUPT
591 || nds32_isr_vectors
[i
].category
== NDS32_ISR_EXCEPTION
)
593 /* Found one vector which is interupt or exception.
594 Output its jmptbl and vector section content. */
595 fprintf (asm_out_file
, "\t! interrupt/exception vector %02d\n", i
);
596 fprintf (asm_out_file
, "\t! ------------------------------------\n");
597 nds32_emit_isr_jmptbl_section (i
);
598 fprintf (asm_out_file
, "\t! ....................................\n");
599 nds32_emit_isr_vector_section (i
);
600 fprintf (asm_out_file
, "\t! ------------------------------------\n");
605 /* Return true if FUNC is a isr function. */
607 nds32_isr_function_p (tree func
)
615 if (TREE_CODE (func
) != FUNCTION_DECL
)
618 attrs
= DECL_ATTRIBUTES (func
);
620 t_intr
= lookup_attribute ("interrupt", attrs
);
621 t_excp
= lookup_attribute ("exception", attrs
);
622 t_reset
= lookup_attribute ("reset", attrs
);
624 return ((t_intr
!= NULL_TREE
)
625 || (t_excp
!= NULL_TREE
)
626 || (t_reset
!= NULL_TREE
));
629 /* ------------------------------------------------------------------------ */