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"
28 #include "stor-layout.h"
33 #include "hard-reg-set.h"
34 #include "insn-config.h" /* Required by recog.h. */
35 #include "conditions.h"
37 #include "insn-attr.h" /* For DFA state_t. */
38 #include "insn-codes.h" /* For CODE_FOR_xxx. */
39 #include "reload.h" /* For push_reload(). */
49 #include "diagnostic-core.h"
50 #include "dominance.h"
56 #include "cfgcleanup.h"
58 #include "basic-block.h"
61 #include "tm-constrs.h"
62 #include "optabs.h" /* For GEN_FCN. */
64 #include "target-def.h"
65 #include "langhooks.h" /* For add_builtin_function(). */
69 /* ------------------------------------------------------------------------ */
71 /* Refer to nds32.h, there are maximum 73 isr vectors in nds32 architecture.
72 0 for reset handler with __attribute__((reset())),
73 1-8 for exception handler with __attribute__((exception(1,...,8))),
74 and 9-72 for interrupt handler with __attribute__((interrupt(0,...,63))).
75 We use an array to record essential information for each vector. */
76 static struct nds32_isr_info nds32_isr_vectors
[NDS32_N_ISR_VECTORS
];
78 /* ------------------------------------------------------------------------ */
80 /* A helper function to emit section head template. */
82 nds32_emit_section_head_template (char section_name
[],
87 const char *flags_str
;
90 flags_str
= (object_p
) ? "\"a\"" : "\"ax\"";
91 type_str
= (object_p
) ? "@object" : "@function";
93 fprintf (asm_out_file
, "\t.section\t%s, %s\n", section_name
, flags_str
);
94 fprintf (asm_out_file
, "\t.align\t%d\n", align_value
);
95 fprintf (asm_out_file
, "\t.global\t%s\n", symbol_name
);
96 fprintf (asm_out_file
, "\t.type\t%s, %s\n", symbol_name
, type_str
);
97 fprintf (asm_out_file
, "%s:\n", symbol_name
);
100 /* A helper function to emit section tail template. */
102 nds32_emit_section_tail_template (char symbol_name
[])
104 fprintf (asm_out_file
, "\t.size\t%s, .-%s\n", symbol_name
, symbol_name
);
107 /* Function to emit isr jump table section. */
109 nds32_emit_isr_jmptbl_section (int vector_id
)
111 char section_name
[100];
112 char symbol_name
[100];
114 /* Prepare jmptbl section and symbol name. */
115 snprintf (section_name
, sizeof (section_name
),
116 ".nds32_jmptbl.%02d", vector_id
);
117 snprintf (symbol_name
, sizeof (symbol_name
),
118 "_nds32_jmptbl_%02d", vector_id
);
120 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
121 fprintf (asm_out_file
, "\t.word\t%s\n",
122 nds32_isr_vectors
[vector_id
].func_name
);
123 nds32_emit_section_tail_template (symbol_name
);
126 /* Function to emit isr vector section. */
128 nds32_emit_isr_vector_section (int vector_id
)
130 unsigned int vector_number_offset
= 0;
131 const char *c_str
= "CATEGORY";
132 const char *sr_str
= "SR";
133 const char *nt_str
= "NT";
134 const char *vs_str
= "VS";
135 char first_level_handler_name
[100];
136 char section_name
[100];
137 char symbol_name
[100];
139 /* Set the vector number offset so that we can calculate
140 the value that user specifies in the attribute.
141 We also prepare the category string for first level handler name. */
142 switch (nds32_isr_vectors
[vector_id
].category
)
144 case NDS32_ISR_INTERRUPT
:
145 vector_number_offset
= 9;
148 case NDS32_ISR_EXCEPTION
:
149 vector_number_offset
= 0;
153 case NDS32_ISR_RESET
:
154 /* Normally it should not be here. */
159 /* Prepare save reg string for first level handler name. */
160 switch (nds32_isr_vectors
[vector_id
].save_reg
)
165 case NDS32_PARTIAL_SAVE
:
170 /* Prepare nested type string for first level handler name. */
171 switch (nds32_isr_vectors
[vector_id
].nested_type
)
176 case NDS32_NOT_NESTED
:
179 case NDS32_NESTED_READY
:
184 /* Currently we have 4-byte or 16-byte size for each vector.
185 If it is 4-byte, the first level handler name has suffix string "_4b". */
186 vs_str
= (nds32_isr_vector_size
== 4) ? "_4b" : "";
188 /* Now we can create first level handler name. */
189 snprintf (first_level_handler_name
, sizeof (first_level_handler_name
),
190 "_nds32_%s_%s_%s%s", c_str
, sr_str
, nt_str
, vs_str
);
192 /* Prepare vector section and symbol name. */
193 snprintf (section_name
, sizeof (section_name
),
194 ".nds32_vector.%02d", vector_id
);
195 snprintf (symbol_name
, sizeof (symbol_name
),
196 "_nds32_vector_%02d%s", vector_id
, vs_str
);
199 /* Everything is ready. We can start emit vector section content. */
200 nds32_emit_section_head_template (section_name
, symbol_name
,
201 floor_log2 (nds32_isr_vector_size
), false);
203 /* According to the vector size, the instructions in the
204 vector section may be different. */
205 if (nds32_isr_vector_size
== 4)
207 /* This block is for 4-byte vector size.
208 Hardware $VID support is necessary and only one instruction
209 is needed in vector section. */
210 fprintf (asm_out_file
, "\tj\t%s ! jump to first level handler\n",
211 first_level_handler_name
);
215 /* This block is for 16-byte vector size.
216 There is NO hardware $VID so that we need several instructions
217 such as pushing GPRs and preparing software vid at vector section.
218 For pushing GPRs, there are four variations for
219 16-byte vector content and we have to handle each combination.
220 For preparing software vid, note that the vid need to
221 be substracted vector_number_offset. */
222 if (TARGET_REDUCED_REGS
)
224 if (nds32_isr_vectors
[vector_id
].save_reg
== NDS32_SAVE_ALL
)
226 /* Case of reduced set registers and save_all attribute. */
227 fprintf (asm_out_file
, "\t! reduced set regs + save_all\n");
228 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r15, 0xf\n");
229 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r10, 0x0\n");
234 /* Case of reduced set registers and partial_save attribute. */
235 fprintf (asm_out_file
, "\t! reduced set regs + partial_save\n");
236 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r15, 0x2\n");
237 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
242 if (nds32_isr_vectors
[vector_id
].save_reg
== NDS32_SAVE_ALL
)
244 /* Case of full set registers and save_all attribute. */
245 fprintf (asm_out_file
, "\t! full set regs + save_all\n");
246 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r27, 0xf\n");
250 /* Case of full set registers and partial_save attribute. */
251 fprintf (asm_out_file
, "\t! full set regs + partial_save\n");
252 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r27, 0x2\n");
253 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
257 fprintf (asm_out_file
, "\tmovi\t$r0, %d ! preparing software vid\n",
258 vector_id
- vector_number_offset
);
259 fprintf (asm_out_file
, "\tj\t%s ! jump to first level handler\n",
260 first_level_handler_name
);
263 nds32_emit_section_tail_template (symbol_name
);
266 /* Function to emit isr reset handler content.
267 Including all jmptbl/vector references, jmptbl section,
268 vector section, nmi handler section, and warm handler section. */
270 nds32_emit_isr_reset_content (void)
273 unsigned int total_n_vectors
;
275 char reset_handler_name
[100];
276 char section_name
[100];
277 char symbol_name
[100];
279 total_n_vectors
= nds32_isr_vectors
[0].total_n_vectors
;
280 vs_str
= (nds32_isr_vector_size
== 4) ? "_4b" : "";
282 fprintf (asm_out_file
, "\t! RESET HANDLER CONTENT - BEGIN !\n");
284 /* Create references in .rodata according to total number of vectors. */
285 fprintf (asm_out_file
, "\t.section\t.rodata\n");
286 fprintf (asm_out_file
, "\t.align\t2\n");
288 /* Emit jmptbl references. */
289 fprintf (asm_out_file
, "\t ! references to jmptbl section entries\n");
290 for (i
= 0; i
< total_n_vectors
; i
++)
291 fprintf (asm_out_file
, "\t.word\t_nds32_jmptbl_%02d\n", i
);
293 /* Emit vector references. */
294 fprintf (asm_out_file
, "\t ! references to vector section entries\n");
295 for (i
= 0; i
< total_n_vectors
; i
++)
296 fprintf (asm_out_file
, "\t.word\t_nds32_vector_%02d%s\n", i
, vs_str
);
298 /* Emit jmptbl_00 section. */
299 snprintf (section_name
, sizeof (section_name
), ".nds32_jmptbl.00");
300 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_jmptbl_00");
302 fprintf (asm_out_file
, "\t! ....................................\n");
303 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
304 fprintf (asm_out_file
, "\t.word\t%s\n",
305 nds32_isr_vectors
[0].func_name
);
306 nds32_emit_section_tail_template (symbol_name
);
308 /* Emit vector_00 section. */
309 snprintf (section_name
, sizeof (section_name
), ".nds32_vector.00");
310 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_vector_00%s", vs_str
);
311 snprintf (reset_handler_name
, sizeof (reset_handler_name
),
312 "_nds32_reset%s", vs_str
);
314 fprintf (asm_out_file
, "\t! ....................................\n");
315 nds32_emit_section_head_template (section_name
, symbol_name
,
316 floor_log2 (nds32_isr_vector_size
), false);
317 fprintf (asm_out_file
, "\tj\t%s ! jump to reset handler\n",
319 nds32_emit_section_tail_template (symbol_name
);
321 /* Emit nmi handler section. */
322 snprintf (section_name
, sizeof (section_name
), ".nds32_nmih");
323 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_nmih");
325 fprintf (asm_out_file
, "\t! ....................................\n");
326 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
327 fprintf (asm_out_file
, "\t.word\t%s\n",
328 (strlen (nds32_isr_vectors
[0].nmi_name
) == 0)
330 : nds32_isr_vectors
[0].nmi_name
);
331 nds32_emit_section_tail_template (symbol_name
);
333 /* Emit warm handler section. */
334 snprintf (section_name
, sizeof (section_name
), ".nds32_wrh");
335 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_wrh");
337 fprintf (asm_out_file
, "\t! ....................................\n");
338 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
339 fprintf (asm_out_file
, "\t.word\t%s\n",
340 (strlen (nds32_isr_vectors
[0].warm_name
) == 0)
342 : nds32_isr_vectors
[0].warm_name
);
343 nds32_emit_section_tail_template (symbol_name
);
345 fprintf (asm_out_file
, "\t! RESET HANDLER CONTENT - END !\n");
348 /* Function for nds32_merge_decl_attributes() and nds32_insert_attributes()
349 to check if there are any conflict isr-specific attributes being set.
351 1. Only 'save_all' or 'partial_save' in the attributes.
352 2. Only 'nested', 'not_nested', or 'nested_ready' in the attributes.
353 3. Only 'interrupt', 'exception', or 'reset' in the attributes. */
355 nds32_check_isr_attrs_conflict (tree func_decl
, tree func_attrs
)
357 int save_all_p
, partial_save_p
;
358 int nested_p
, not_nested_p
, nested_ready_p
;
359 int intr_p
, excp_p
, reset_p
;
361 /* Initialize variables. */
362 save_all_p
= partial_save_p
= 0;
363 nested_p
= not_nested_p
= nested_ready_p
= 0;
364 intr_p
= excp_p
= reset_p
= 0;
366 /* We must check at MOST one attribute to set save-reg. */
367 if (lookup_attribute ("save_all", func_attrs
))
369 if (lookup_attribute ("partial_save", func_attrs
))
372 if ((save_all_p
+ partial_save_p
) > 1)
373 error ("multiple save reg attributes to function %qD", func_decl
);
375 /* We must check at MOST one attribute to set nested-type. */
376 if (lookup_attribute ("nested", func_attrs
))
378 if (lookup_attribute ("not_nested", func_attrs
))
380 if (lookup_attribute ("nested_ready", func_attrs
))
383 if ((nested_p
+ not_nested_p
+ nested_ready_p
) > 1)
384 error ("multiple nested types attributes to function %qD", func_decl
);
386 /* We must check at MOST one attribute to
387 set interrupt/exception/reset. */
388 if (lookup_attribute ("interrupt", func_attrs
))
390 if (lookup_attribute ("exception", func_attrs
))
392 if (lookup_attribute ("reset", func_attrs
))
395 if ((intr_p
+ excp_p
+ reset_p
) > 1)
396 error ("multiple interrupt attributes to function %qD", func_decl
);
399 /* Function to construct isr vectors information array.
400 We DO NOT HAVE TO check if the attributes are valid
401 because those works are supposed to be done on
402 nds32_merge_decl_attributes() and nds32_insert_attributes(). */
404 nds32_construct_isr_vectors_information (tree func_attrs
,
405 const char *func_name
)
407 tree save_all
, partial_save
;
408 tree nested
, not_nested
, nested_ready
;
409 tree intr
, excp
, reset
;
411 save_all
= lookup_attribute ("save_all", func_attrs
);
412 partial_save
= lookup_attribute ("partial_save", func_attrs
);
414 nested
= lookup_attribute ("nested", func_attrs
);
415 not_nested
= lookup_attribute ("not_nested", func_attrs
);
416 nested_ready
= lookup_attribute ("nested_ready", func_attrs
);
418 intr
= lookup_attribute ("interrupt", func_attrs
);
419 excp
= lookup_attribute ("exception", func_attrs
);
420 reset
= lookup_attribute ("reset", func_attrs
);
422 /* If there is no interrupt/exception/reset, we can return immediately. */
423 if (!intr
&& !excp
&& !reset
)
426 /* If we are here, either we have interrupt/exception,
427 or reset attribute. */
432 /* Prepare id list so that we can traverse and set vector id. */
433 id_list
= (intr
) ? (TREE_VALUE (intr
)) : (TREE_VALUE (excp
));
439 unsigned int vector_number_offset
;
441 /* The way to handle interrupt or exception is the same,
442 we just need to take care of actual vector number.
443 For interrupt(0..63), the actual vector number is (9..72).
444 For exception(1..8), the actual vector number is (1..8). */
445 vector_number_offset
= (intr
) ? (9) : (0);
447 /* Pick up each vector id value. */
448 id
= TREE_VALUE (id_list
);
449 /* Add vector_number_offset to get actual vector number. */
450 vector_id
= TREE_INT_CST_LOW (id
) + vector_number_offset
;
452 /* Enable corresponding vector and set function name. */
453 nds32_isr_vectors
[vector_id
].category
= (intr
)
454 ? (NDS32_ISR_INTERRUPT
)
455 : (NDS32_ISR_EXCEPTION
);
456 strcpy (nds32_isr_vectors
[vector_id
].func_name
, func_name
);
458 /* Set register saving scheme. */
460 nds32_isr_vectors
[vector_id
].save_reg
= NDS32_SAVE_ALL
;
461 else if (partial_save
)
462 nds32_isr_vectors
[vector_id
].save_reg
= NDS32_PARTIAL_SAVE
;
464 /* Set nested type. */
466 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NESTED
;
468 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NOT_NESTED
;
469 else if (nested_ready
)
470 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NESTED_READY
;
472 /* Advance to next id. */
473 id_list
= TREE_CHAIN (id_list
);
482 /* Deal with reset attribute. Its vector number is always 0. */
483 nds32_isr_vectors
[0].category
= NDS32_ISR_RESET
;
485 /* Prepare id_list and identify id value so that
486 we can set total number of vectors. */
487 id_list
= TREE_VALUE (reset
);
488 id
= TREE_VALUE (id_list
);
490 /* The total vectors = interrupt + exception numbers + reset.
491 There are 8 exception and 1 reset in nds32 architecture. */
492 nds32_isr_vectors
[0].total_n_vectors
= TREE_INT_CST_LOW (id
) + 8 + 1;
493 strcpy (nds32_isr_vectors
[0].func_name
, func_name
);
495 /* Retrieve nmi and warm function. */
496 nmi
= lookup_attribute ("nmi", func_attrs
);
497 warm
= lookup_attribute ("warm", func_attrs
);
499 if (nmi
!= NULL_TREE
)
504 nmi_func_list
= TREE_VALUE (nmi
);
505 nmi_func
= TREE_VALUE (nmi_func_list
);
507 /* Record nmi function name. */
508 strcpy (nds32_isr_vectors
[0].nmi_name
,
509 IDENTIFIER_POINTER (nmi_func
));
512 if (warm
!= NULL_TREE
)
517 warm_func_list
= TREE_VALUE (warm
);
518 warm_func
= TREE_VALUE (warm_func_list
);
520 /* Record warm function name. */
521 strcpy (nds32_isr_vectors
[0].warm_name
,
522 IDENTIFIER_POINTER (warm_func
));
527 /* A helper function to handle isr stuff at the beginning of asm file. */
529 nds32_asm_file_start_for_isr (void)
533 /* Initialize isr vector information array before compiling functions. */
534 for (i
= 0; i
< NDS32_N_ISR_VECTORS
; i
++)
536 nds32_isr_vectors
[i
].category
= NDS32_ISR_NONE
;
537 strcpy (nds32_isr_vectors
[i
].func_name
, "");
538 nds32_isr_vectors
[i
].save_reg
= NDS32_PARTIAL_SAVE
;
539 nds32_isr_vectors
[i
].nested_type
= NDS32_NOT_NESTED
;
540 nds32_isr_vectors
[i
].total_n_vectors
= 0;
541 strcpy (nds32_isr_vectors
[i
].nmi_name
, "");
542 strcpy (nds32_isr_vectors
[i
].warm_name
, "");
546 /* A helper function to handle isr stuff at the end of asm file. */
548 nds32_asm_file_end_for_isr (void)
552 /* If all the vectors are NDS32_ISR_NONE, we can return immediately. */
553 for (i
= 0; i
< NDS32_N_ISR_VECTORS
; i
++)
554 if (nds32_isr_vectors
[i
].category
!= NDS32_ISR_NONE
)
557 if (i
== NDS32_N_ISR_VECTORS
)
560 /* At least one vector is NOT NDS32_ISR_NONE,
561 we should output isr vector information. */
562 fprintf (asm_out_file
, "\t! ------------------------------------\n");
563 fprintf (asm_out_file
, "\t! The isr vector information:\n");
564 fprintf (asm_out_file
, "\t! ------------------------------------\n");
566 /* Check reset handler first. Its vector number is always 0. */
567 if (nds32_isr_vectors
[0].category
== NDS32_ISR_RESET
)
569 nds32_emit_isr_reset_content ();
570 fprintf (asm_out_file
, "\t! ------------------------------------\n");
573 /* Check other vectors, starting from vector number 1. */
574 for (i
= 1; i
< NDS32_N_ISR_VECTORS
; i
++)
576 if (nds32_isr_vectors
[i
].category
== NDS32_ISR_INTERRUPT
577 || nds32_isr_vectors
[i
].category
== NDS32_ISR_EXCEPTION
)
579 /* Found one vector which is interupt or exception.
580 Output its jmptbl and vector section content. */
581 fprintf (asm_out_file
, "\t! interrupt/exception vector %02d\n", i
);
582 fprintf (asm_out_file
, "\t! ------------------------------------\n");
583 nds32_emit_isr_jmptbl_section (i
);
584 fprintf (asm_out_file
, "\t! ....................................\n");
585 nds32_emit_isr_vector_section (i
);
586 fprintf (asm_out_file
, "\t! ------------------------------------\n");
591 /* Return true if FUNC is a isr function. */
593 nds32_isr_function_p (tree func
)
601 if (TREE_CODE (func
) != FUNCTION_DECL
)
604 attrs
= DECL_ATTRIBUTES (func
);
606 t_intr
= lookup_attribute ("interrupt", attrs
);
607 t_excp
= lookup_attribute ("exception", attrs
);
608 t_reset
= lookup_attribute ("reset", attrs
);
610 return ((t_intr
!= NULL_TREE
)
611 || (t_excp
!= NULL_TREE
)
612 || (t_reset
!= NULL_TREE
));
615 /* ------------------------------------------------------------------------ */