1 /* Subroutines used for ISR of Andes NDS32 cpu for GNU compiler
2 Copyright (C) 2012-2014 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"
52 #include "tm-constrs.h"
53 #include "optabs.h" /* For GEN_FCN. */
55 #include "target-def.h"
56 #include "langhooks.h" /* For add_builtin_function(). */
60 /* ------------------------------------------------------------------------ */
62 /* Refer to nds32.h, there are maximum 73 isr vectors in nds32 architecture.
63 0 for reset handler with __attribute__((reset())),
64 1-8 for exception handler with __attribute__((exception(1,...,8))),
65 and 9-72 for interrupt handler with __attribute__((interrupt(0,...,63))).
66 We use an array to record essential information for each vector. */
67 static struct nds32_isr_info nds32_isr_vectors
[NDS32_N_ISR_VECTORS
];
69 /* ------------------------------------------------------------------------ */
71 /* A helper function to emit section head template. */
73 nds32_emit_section_head_template (char section_name
[],
78 const char *flags_str
;
81 flags_str
= (object_p
) ? "\"a\"" : "\"ax\"";
82 type_str
= (object_p
) ? "@object" : "@function";
84 fprintf (asm_out_file
, "\t.section\t%s, %s\n", section_name
, flags_str
);
85 fprintf (asm_out_file
, "\t.align\t%d\n", align_value
);
86 fprintf (asm_out_file
, "\t.global\t%s\n", symbol_name
);
87 fprintf (asm_out_file
, "\t.type\t%s, %s\n", symbol_name
, type_str
);
88 fprintf (asm_out_file
, "%s:\n", symbol_name
);
91 /* A helper function to emit section tail template. */
93 nds32_emit_section_tail_template (char symbol_name
[])
95 fprintf (asm_out_file
, "\t.size\t%s, .-%s\n", symbol_name
, symbol_name
);
98 /* Function to emit isr jump table section. */
100 nds32_emit_isr_jmptbl_section (int vector_id
)
102 char section_name
[100];
103 char symbol_name
[100];
105 /* Prepare jmptbl section and symbol name. */
106 snprintf (section_name
, sizeof (section_name
),
107 ".nds32_jmptbl.%02d", vector_id
);
108 snprintf (symbol_name
, sizeof (symbol_name
),
109 "_nds32_jmptbl_%02d", vector_id
);
111 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
112 fprintf (asm_out_file
, "\t.word\t%s\n",
113 nds32_isr_vectors
[vector_id
].func_name
);
114 nds32_emit_section_tail_template (symbol_name
);
117 /* Function to emit isr vector section. */
119 nds32_emit_isr_vector_section (int vector_id
)
121 unsigned int vector_number_offset
= 0;
122 const char *c_str
= "CATEGORY";
123 const char *sr_str
= "SR";
124 const char *nt_str
= "NT";
125 const char *vs_str
= "VS";
126 char first_level_handler_name
[100];
127 char section_name
[100];
128 char symbol_name
[100];
130 /* Set the vector number offset so that we can calculate
131 the value that user specifies in the attribute.
132 We also prepare the category string for first level handler name. */
133 switch (nds32_isr_vectors
[vector_id
].category
)
135 case NDS32_ISR_INTERRUPT
:
136 vector_number_offset
= 9;
139 case NDS32_ISR_EXCEPTION
:
140 vector_number_offset
= 0;
144 case NDS32_ISR_RESET
:
145 /* Normally it should not be here. */
150 /* Prepare save reg string for first level handler name. */
151 switch (nds32_isr_vectors
[vector_id
].save_reg
)
156 case NDS32_PARTIAL_SAVE
:
161 /* Prepare nested type string for first level handler name. */
162 switch (nds32_isr_vectors
[vector_id
].nested_type
)
167 case NDS32_NOT_NESTED
:
170 case NDS32_NESTED_READY
:
175 /* Currently we have 4-byte or 16-byte size for each vector.
176 If it is 4-byte, the first level handler name has suffix string "_4b". */
177 vs_str
= (nds32_isr_vector_size
== 4) ? "_4b" : "";
179 /* Now we can create first level handler name. */
180 snprintf (first_level_handler_name
, sizeof (first_level_handler_name
),
181 "_nds32_%s_%s_%s%s", c_str
, sr_str
, nt_str
, vs_str
);
183 /* Prepare vector section and symbol name. */
184 snprintf (section_name
, sizeof (section_name
),
185 ".nds32_vector.%02d", vector_id
);
186 snprintf (symbol_name
, sizeof (symbol_name
),
187 "_nds32_vector_%02d%s", vector_id
, vs_str
);
190 /* Everything is ready. We can start emit vector section content. */
191 nds32_emit_section_head_template (section_name
, symbol_name
,
192 floor_log2 (nds32_isr_vector_size
), false);
194 /* According to the vector size, the instructions in the
195 vector section may be different. */
196 if (nds32_isr_vector_size
== 4)
198 /* This block is for 4-byte vector size.
199 Hardware $VID support is necessary and only one instruction
200 is needed in vector section. */
201 fprintf (asm_out_file
, "\tj\t%s ! jump to first level handler\n",
202 first_level_handler_name
);
206 /* This block is for 16-byte vector size.
207 There is NO hardware $VID so that we need several instructions
208 such as pushing GPRs and preparing software vid at vector section.
209 For pushing GPRs, there are four variations for
210 16-byte vector content and we have to handle each combination.
211 For preparing software vid, note that the vid need to
212 be substracted vector_number_offset. */
213 if (TARGET_REDUCED_REGS
)
215 if (nds32_isr_vectors
[vector_id
].save_reg
== NDS32_SAVE_ALL
)
217 /* Case of reduced set registers and save_all attribute. */
218 fprintf (asm_out_file
, "\t! reduced set regs + save_all\n");
219 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r15, 0xf\n");
220 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r10, 0x0\n");
225 /* Case of reduced set registers and partial_save attribute. */
226 fprintf (asm_out_file
, "\t! reduced set regs + partial_save\n");
227 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r15, 0x2\n");
228 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
233 if (nds32_isr_vectors
[vector_id
].save_reg
== NDS32_SAVE_ALL
)
235 /* Case of full set registers and save_all attribute. */
236 fprintf (asm_out_file
, "\t! full set regs + save_all\n");
237 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r27, 0xf\n");
241 /* Case of full set registers and partial_save attribute. */
242 fprintf (asm_out_file
, "\t! full set regs + partial_save\n");
243 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r27, 0x2\n");
244 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
248 fprintf (asm_out_file
, "\tmovi\t$r0, %d ! preparing software vid\n",
249 vector_id
- vector_number_offset
);
250 fprintf (asm_out_file
, "\tj\t%s ! jump to first level handler\n",
251 first_level_handler_name
);
254 nds32_emit_section_tail_template (symbol_name
);
257 /* Function to emit isr reset handler content.
258 Including all jmptbl/vector references, jmptbl section,
259 vector section, nmi handler section, and warm handler section. */
261 nds32_emit_isr_reset_content (void)
264 unsigned int total_n_vectors
;
266 char reset_handler_name
[100];
267 char section_name
[100];
268 char symbol_name
[100];
270 total_n_vectors
= nds32_isr_vectors
[0].total_n_vectors
;
271 vs_str
= (nds32_isr_vector_size
== 4) ? "_4b" : "";
273 fprintf (asm_out_file
, "\t! RESET HANDLER CONTENT - BEGIN !\n");
275 /* Create references in .rodata according to total number of vectors. */
276 fprintf (asm_out_file
, "\t.section\t.rodata\n");
277 fprintf (asm_out_file
, "\t.align\t2\n");
279 /* Emit jmptbl references. */
280 fprintf (asm_out_file
, "\t ! references to jmptbl section entries\n");
281 for (i
= 0; i
< total_n_vectors
; i
++)
282 fprintf (asm_out_file
, "\t.word\t_nds32_jmptbl_%02d\n", i
);
284 /* Emit vector references. */
285 fprintf (asm_out_file
, "\t ! references to vector section entries\n");
286 for (i
= 0; i
< total_n_vectors
; i
++)
287 fprintf (asm_out_file
, "\t.word\t_nds32_vector_%02d%s\n", i
, vs_str
);
289 /* Emit jmptbl_00 section. */
290 snprintf (section_name
, sizeof (section_name
), ".nds32_jmptbl.00");
291 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_jmptbl_00");
293 fprintf (asm_out_file
, "\t! ....................................\n");
294 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
295 fprintf (asm_out_file
, "\t.word\t%s\n",
296 nds32_isr_vectors
[0].func_name
);
297 nds32_emit_section_tail_template (symbol_name
);
299 /* Emit vector_00 section. */
300 snprintf (section_name
, sizeof (section_name
), ".nds32_vector.00");
301 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_vector_00%s", vs_str
);
302 snprintf (reset_handler_name
, sizeof (reset_handler_name
),
303 "_nds32_reset%s", vs_str
);
305 fprintf (asm_out_file
, "\t! ....................................\n");
306 nds32_emit_section_head_template (section_name
, symbol_name
,
307 floor_log2 (nds32_isr_vector_size
), false);
308 fprintf (asm_out_file
, "\tj\t%s ! jump to reset handler\n",
310 nds32_emit_section_tail_template (symbol_name
);
312 /* Emit nmi handler section. */
313 snprintf (section_name
, sizeof (section_name
), ".nds32_nmih");
314 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_nmih");
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 (strlen (nds32_isr_vectors
[0].nmi_name
) == 0)
321 : nds32_isr_vectors
[0].nmi_name
);
322 nds32_emit_section_tail_template (symbol_name
);
324 /* Emit warm handler section. */
325 snprintf (section_name
, sizeof (section_name
), ".nds32_wrh");
326 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_wrh");
328 fprintf (asm_out_file
, "\t! ....................................\n");
329 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
330 fprintf (asm_out_file
, "\t.word\t%s\n",
331 (strlen (nds32_isr_vectors
[0].warm_name
) == 0)
333 : nds32_isr_vectors
[0].warm_name
);
334 nds32_emit_section_tail_template (symbol_name
);
336 fprintf (asm_out_file
, "\t! RESET HANDLER CONTENT - END !\n");
339 /* Function for nds32_merge_decl_attributes() and nds32_insert_attributes()
340 to check if there are any conflict isr-specific attributes being set.
342 1. Only 'save_all' or 'partial_save' in the attributes.
343 2. Only 'nested', 'not_nested', or 'nested_ready' in the attributes.
344 3. Only 'interrupt', 'exception', or 'reset' in the attributes. */
346 nds32_check_isr_attrs_conflict (tree func_decl
, tree func_attrs
)
348 int save_all_p
, partial_save_p
;
349 int nested_p
, not_nested_p
, nested_ready_p
;
350 int intr_p
, excp_p
, reset_p
;
352 /* Initialize variables. */
353 save_all_p
= partial_save_p
= 0;
354 nested_p
= not_nested_p
= nested_ready_p
= 0;
355 intr_p
= excp_p
= reset_p
= 0;
357 /* We must check at MOST one attribute to set save-reg. */
358 if (lookup_attribute ("save_all", func_attrs
))
360 if (lookup_attribute ("partial_save", func_attrs
))
363 if ((save_all_p
+ partial_save_p
) > 1)
364 error ("multiple save reg attributes to function %qD", func_decl
);
366 /* We must check at MOST one attribute to set nested-type. */
367 if (lookup_attribute ("nested", func_attrs
))
369 if (lookup_attribute ("not_nested", func_attrs
))
371 if (lookup_attribute ("nested_ready", func_attrs
))
374 if ((nested_p
+ not_nested_p
+ nested_ready_p
) > 1)
375 error ("multiple nested types attributes to function %qD", func_decl
);
377 /* We must check at MOST one attribute to
378 set interrupt/exception/reset. */
379 if (lookup_attribute ("interrupt", func_attrs
))
381 if (lookup_attribute ("exception", func_attrs
))
383 if (lookup_attribute ("reset", func_attrs
))
386 if ((intr_p
+ excp_p
+ reset_p
) > 1)
387 error ("multiple interrupt attributes to function %qD", func_decl
);
390 /* Function to construct isr vectors information array.
391 We DO NOT HAVE TO check if the attributes are valid
392 because those works are supposed to be done on
393 nds32_merge_decl_attributes() and nds32_insert_attributes(). */
395 nds32_construct_isr_vectors_information (tree func_attrs
,
396 const char *func_name
)
398 tree save_all
, partial_save
;
399 tree nested
, not_nested
, nested_ready
;
400 tree intr
, excp
, reset
;
402 save_all
= lookup_attribute ("save_all", func_attrs
);
403 partial_save
= lookup_attribute ("partial_save", func_attrs
);
405 nested
= lookup_attribute ("nested", func_attrs
);
406 not_nested
= lookup_attribute ("not_nested", func_attrs
);
407 nested_ready
= lookup_attribute ("nested_ready", func_attrs
);
409 intr
= lookup_attribute ("interrupt", func_attrs
);
410 excp
= lookup_attribute ("exception", func_attrs
);
411 reset
= lookup_attribute ("reset", func_attrs
);
413 /* If there is no interrupt/exception/reset, we can return immediately. */
414 if (!intr
&& !excp
&& !reset
)
417 /* If we are here, either we have interrupt/exception,
418 or reset attribute. */
423 /* Prepare id list so that we can traverse and set vector id. */
424 id_list
= (intr
) ? (TREE_VALUE (intr
)) : (TREE_VALUE (excp
));
430 unsigned int vector_number_offset
;
432 /* The way to handle interrupt or exception is the same,
433 we just need to take care of actual vector number.
434 For interrupt(0..63), the actual vector number is (9..72).
435 For exception(1..8), the actual vector number is (1..8). */
436 vector_number_offset
= (intr
) ? (9) : (0);
438 /* Pick up each vector id value. */
439 id
= TREE_VALUE (id_list
);
440 /* Add vector_number_offset to get actual vector number. */
441 vector_id
= TREE_INT_CST_LOW (id
) + vector_number_offset
;
443 /* Enable corresponding vector and set function name. */
444 nds32_isr_vectors
[vector_id
].category
= (intr
)
445 ? (NDS32_ISR_INTERRUPT
)
446 : (NDS32_ISR_EXCEPTION
);
447 strcpy (nds32_isr_vectors
[vector_id
].func_name
, func_name
);
449 /* Set register saving scheme. */
451 nds32_isr_vectors
[vector_id
].save_reg
= NDS32_SAVE_ALL
;
452 else if (partial_save
)
453 nds32_isr_vectors
[vector_id
].save_reg
= NDS32_PARTIAL_SAVE
;
455 /* Set nested type. */
457 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NESTED
;
459 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NOT_NESTED
;
460 else if (nested_ready
)
461 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NESTED_READY
;
463 /* Advance to next id. */
464 id_list
= TREE_CHAIN (id_list
);
473 /* Deal with reset attribute. Its vector number is always 0. */
474 nds32_isr_vectors
[0].category
= NDS32_ISR_RESET
;
476 /* Prepare id_list and identify id value so that
477 we can set total number of vectors. */
478 id_list
= TREE_VALUE (reset
);
479 id
= TREE_VALUE (id_list
);
481 /* The total vectors = interrupt + exception numbers + reset.
482 There are 8 exception and 1 reset in nds32 architecture. */
483 nds32_isr_vectors
[0].total_n_vectors
= TREE_INT_CST_LOW (id
) + 8 + 1;
484 strcpy (nds32_isr_vectors
[0].func_name
, func_name
);
486 /* Retrieve nmi and warm function. */
487 nmi
= lookup_attribute ("nmi", func_attrs
);
488 warm
= lookup_attribute ("warm", func_attrs
);
490 if (nmi
!= NULL_TREE
)
495 nmi_func_list
= TREE_VALUE (nmi
);
496 nmi_func
= TREE_VALUE (nmi_func_list
);
498 /* Record nmi function name. */
499 strcpy (nds32_isr_vectors
[0].nmi_name
,
500 IDENTIFIER_POINTER (nmi_func
));
503 if (warm
!= NULL_TREE
)
508 warm_func_list
= TREE_VALUE (warm
);
509 warm_func
= TREE_VALUE (warm_func_list
);
511 /* Record warm function name. */
512 strcpy (nds32_isr_vectors
[0].warm_name
,
513 IDENTIFIER_POINTER (warm_func
));
518 /* A helper function to handle isr stuff at the beginning of asm file. */
520 nds32_asm_file_start_for_isr (void)
524 /* Initialize isr vector information array before compiling functions. */
525 for (i
= 0; i
< NDS32_N_ISR_VECTORS
; i
++)
527 nds32_isr_vectors
[i
].category
= NDS32_ISR_NONE
;
528 strcpy (nds32_isr_vectors
[i
].func_name
, "");
529 nds32_isr_vectors
[i
].save_reg
= NDS32_PARTIAL_SAVE
;
530 nds32_isr_vectors
[i
].nested_type
= NDS32_NOT_NESTED
;
531 nds32_isr_vectors
[i
].total_n_vectors
= 0;
532 strcpy (nds32_isr_vectors
[i
].nmi_name
, "");
533 strcpy (nds32_isr_vectors
[i
].warm_name
, "");
537 /* A helper function to handle isr stuff at the end of asm file. */
539 nds32_asm_file_end_for_isr (void)
543 /* If all the vectors are NDS32_ISR_NONE, we can return immediately. */
544 for (i
= 0; i
< NDS32_N_ISR_VECTORS
; i
++)
545 if (nds32_isr_vectors
[i
].category
!= NDS32_ISR_NONE
)
548 if (i
== NDS32_N_ISR_VECTORS
)
551 /* At least one vector is NOT NDS32_ISR_NONE,
552 we should output isr vector information. */
553 fprintf (asm_out_file
, "\t! ------------------------------------\n");
554 fprintf (asm_out_file
, "\t! The isr vector information:\n");
555 fprintf (asm_out_file
, "\t! ------------------------------------\n");
557 /* Check reset handler first. Its vector number is always 0. */
558 if (nds32_isr_vectors
[0].category
== NDS32_ISR_RESET
)
560 nds32_emit_isr_reset_content ();
561 fprintf (asm_out_file
, "\t! ------------------------------------\n");
564 /* Check other vectors, starting from vector number 1. */
565 for (i
= 1; i
< NDS32_N_ISR_VECTORS
; i
++)
567 if (nds32_isr_vectors
[i
].category
== NDS32_ISR_INTERRUPT
568 || nds32_isr_vectors
[i
].category
== NDS32_ISR_EXCEPTION
)
570 /* Found one vector which is interupt or exception.
571 Output its jmptbl and vector section content. */
572 fprintf (asm_out_file
, "\t! interrupt/exception vector %02d\n", i
);
573 fprintf (asm_out_file
, "\t! ------------------------------------\n");
574 nds32_emit_isr_jmptbl_section (i
);
575 fprintf (asm_out_file
, "\t! ....................................\n");
576 nds32_emit_isr_vector_section (i
);
577 fprintf (asm_out_file
, "\t! ------------------------------------\n");
582 /* Return true if FUNC is a isr function. */
584 nds32_isr_function_p (tree func
)
592 if (TREE_CODE (func
) != FUNCTION_DECL
)
595 attrs
= DECL_ATTRIBUTES (func
);
597 t_intr
= lookup_attribute ("interrupt", attrs
);
598 t_excp
= lookup_attribute ("exception", attrs
);
599 t_reset
= lookup_attribute ("reset", attrs
);
601 return ((t_intr
!= NULL_TREE
)
602 || (t_excp
!= NULL_TREE
)
603 || (t_reset
!= NULL_TREE
));
606 /* ------------------------------------------------------------------------ */