1 /* Subroutines used for ISR of Andes NDS32 cpu for GNU compiler
2 Copyright (C) 2012-2017 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 "stringpool.h"
32 #include "diagnostic-core.h"
35 /* ------------------------------------------------------------------------ */
37 /* Refer to nds32.h, there are maximum 73 isr vectors in nds32 architecture.
38 0 for reset handler with __attribute__((reset())),
39 1-8 for exception handler with __attribute__((exception(1,...,8))),
40 and 9-72 for interrupt handler with __attribute__((interrupt(0,...,63))).
41 We use an array to record essential information for each vector. */
42 static struct nds32_isr_info nds32_isr_vectors
[NDS32_N_ISR_VECTORS
];
44 /* ------------------------------------------------------------------------ */
46 /* A helper function to emit section head template. */
48 nds32_emit_section_head_template (char section_name
[],
53 const char *flags_str
;
56 flags_str
= (object_p
) ? "\"a\"" : "\"ax\"";
57 type_str
= (object_p
) ? "@object" : "@function";
59 fprintf (asm_out_file
, "\t.section\t%s, %s\n", section_name
, flags_str
);
60 fprintf (asm_out_file
, "\t.align\t%d\n", align_value
);
61 fprintf (asm_out_file
, "\t.global\t%s\n", symbol_name
);
62 fprintf (asm_out_file
, "\t.type\t%s, %s\n", symbol_name
, type_str
);
63 fprintf (asm_out_file
, "%s:\n", symbol_name
);
66 /* A helper function to emit section tail template. */
68 nds32_emit_section_tail_template (char symbol_name
[])
70 fprintf (asm_out_file
, "\t.size\t%s, .-%s\n", symbol_name
, symbol_name
);
73 /* Function to emit isr jump table section. */
75 nds32_emit_isr_jmptbl_section (int vector_id
)
77 char section_name
[100];
78 char symbol_name
[100];
80 /* Prepare jmptbl section and symbol name. */
81 snprintf (section_name
, sizeof (section_name
),
82 ".nds32_jmptbl.%02d", vector_id
);
83 snprintf (symbol_name
, sizeof (symbol_name
),
84 "_nds32_jmptbl_%02d", vector_id
);
86 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
87 fprintf (asm_out_file
, "\t.word\t%s\n",
88 nds32_isr_vectors
[vector_id
].func_name
);
89 nds32_emit_section_tail_template (symbol_name
);
92 /* Function to emit isr vector section. */
94 nds32_emit_isr_vector_section (int vector_id
)
96 unsigned int vector_number_offset
= 0;
97 const char *c_str
= "CATEGORY";
98 const char *sr_str
= "SR";
99 const char *nt_str
= "NT";
100 const char *vs_str
= "VS";
101 char first_level_handler_name
[100];
102 char section_name
[100];
103 char symbol_name
[100];
105 /* Set the vector number offset so that we can calculate
106 the value that user specifies in the attribute.
107 We also prepare the category string for first level handler name. */
108 switch (nds32_isr_vectors
[vector_id
].category
)
110 case NDS32_ISR_INTERRUPT
:
111 vector_number_offset
= 9;
114 case NDS32_ISR_EXCEPTION
:
115 vector_number_offset
= 0;
119 case NDS32_ISR_RESET
:
120 /* Normally it should not be here. */
125 /* Prepare save reg string for first level handler name. */
126 switch (nds32_isr_vectors
[vector_id
].save_reg
)
131 case NDS32_PARTIAL_SAVE
:
136 /* Prepare nested type string for first level handler name. */
137 switch (nds32_isr_vectors
[vector_id
].nested_type
)
142 case NDS32_NOT_NESTED
:
145 case NDS32_NESTED_READY
:
150 /* Currently we have 4-byte or 16-byte size for each vector.
151 If it is 4-byte, the first level handler name has suffix string "_4b". */
152 vs_str
= (nds32_isr_vector_size
== 4) ? "_4b" : "";
154 /* Now we can create first level handler name. */
155 snprintf (first_level_handler_name
, sizeof (first_level_handler_name
),
156 "_nds32_%s_%s_%s%s", c_str
, sr_str
, nt_str
, vs_str
);
158 /* Prepare vector section and symbol name. */
159 snprintf (section_name
, sizeof (section_name
),
160 ".nds32_vector.%02d", vector_id
);
161 snprintf (symbol_name
, sizeof (symbol_name
),
162 "_nds32_vector_%02d%s", vector_id
, vs_str
);
165 /* Everything is ready. We can start emit vector section content. */
166 nds32_emit_section_head_template (section_name
, symbol_name
,
167 floor_log2 (nds32_isr_vector_size
), false);
169 /* According to the vector size, the instructions in the
170 vector section may be different. */
171 if (nds32_isr_vector_size
== 4)
173 /* This block is for 4-byte vector size.
174 Hardware $VID support is necessary and only one instruction
175 is needed in vector section. */
176 fprintf (asm_out_file
, "\tj\t%s ! jump to first level handler\n",
177 first_level_handler_name
);
181 /* This block is for 16-byte vector size.
182 There is NO hardware $VID so that we need several instructions
183 such as pushing GPRs and preparing software vid at vector section.
184 For pushing GPRs, there are four variations for
185 16-byte vector content and we have to handle each combination.
186 For preparing software vid, note that the vid need to
187 be substracted vector_number_offset. */
188 if (TARGET_REDUCED_REGS
)
190 if (nds32_isr_vectors
[vector_id
].save_reg
== NDS32_SAVE_ALL
)
192 /* Case of reduced set registers and save_all attribute. */
193 fprintf (asm_out_file
, "\t! reduced set regs + save_all\n");
194 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r15, 0xf\n");
195 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r10, 0x0\n");
200 /* Case of reduced set registers and partial_save attribute. */
201 fprintf (asm_out_file
, "\t! reduced set regs + partial_save\n");
202 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r15, 0x2\n");
203 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
208 if (nds32_isr_vectors
[vector_id
].save_reg
== NDS32_SAVE_ALL
)
210 /* Case of full set registers and save_all attribute. */
211 fprintf (asm_out_file
, "\t! full set regs + save_all\n");
212 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r27, 0xf\n");
216 /* Case of full set registers and partial_save attribute. */
217 fprintf (asm_out_file
, "\t! full set regs + partial_save\n");
218 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r27, 0x2\n");
219 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
223 fprintf (asm_out_file
, "\tmovi\t$r0, %d ! preparing software vid\n",
224 vector_id
- vector_number_offset
);
225 fprintf (asm_out_file
, "\tj\t%s ! jump to first level handler\n",
226 first_level_handler_name
);
229 nds32_emit_section_tail_template (symbol_name
);
232 /* Function to emit isr reset handler content.
233 Including all jmptbl/vector references, jmptbl section,
234 vector section, nmi handler section, and warm handler section. */
236 nds32_emit_isr_reset_content (void)
239 unsigned int total_n_vectors
;
241 char reset_handler_name
[100];
242 char section_name
[100];
243 char symbol_name
[100];
245 total_n_vectors
= nds32_isr_vectors
[0].total_n_vectors
;
246 vs_str
= (nds32_isr_vector_size
== 4) ? "_4b" : "";
248 fprintf (asm_out_file
, "\t! RESET HANDLER CONTENT - BEGIN !\n");
250 /* Create references in .rodata according to total number of vectors. */
251 fprintf (asm_out_file
, "\t.section\t.rodata\n");
252 fprintf (asm_out_file
, "\t.align\t2\n");
254 /* Emit jmptbl references. */
255 fprintf (asm_out_file
, "\t ! references to jmptbl section entries\n");
256 for (i
= 0; i
< total_n_vectors
; i
++)
257 fprintf (asm_out_file
, "\t.word\t_nds32_jmptbl_%02d\n", i
);
259 /* Emit vector references. */
260 fprintf (asm_out_file
, "\t ! references to vector section entries\n");
261 for (i
= 0; i
< total_n_vectors
; i
++)
262 fprintf (asm_out_file
, "\t.word\t_nds32_vector_%02d%s\n", i
, vs_str
);
264 /* Emit jmptbl_00 section. */
265 snprintf (section_name
, sizeof (section_name
), ".nds32_jmptbl.00");
266 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_jmptbl_00");
268 fprintf (asm_out_file
, "\t! ....................................\n");
269 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
270 fprintf (asm_out_file
, "\t.word\t%s\n",
271 nds32_isr_vectors
[0].func_name
);
272 nds32_emit_section_tail_template (symbol_name
);
274 /* Emit vector_00 section. */
275 snprintf (section_name
, sizeof (section_name
), ".nds32_vector.00");
276 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_vector_00%s", vs_str
);
277 snprintf (reset_handler_name
, sizeof (reset_handler_name
),
278 "_nds32_reset%s", vs_str
);
280 fprintf (asm_out_file
, "\t! ....................................\n");
281 nds32_emit_section_head_template (section_name
, symbol_name
,
282 floor_log2 (nds32_isr_vector_size
), false);
283 fprintf (asm_out_file
, "\tj\t%s ! jump to reset handler\n",
285 nds32_emit_section_tail_template (symbol_name
);
287 /* Emit nmi handler section. */
288 snprintf (section_name
, sizeof (section_name
), ".nds32_nmih");
289 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_nmih");
291 fprintf (asm_out_file
, "\t! ....................................\n");
292 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
293 fprintf (asm_out_file
, "\t.word\t%s\n",
294 (strlen (nds32_isr_vectors
[0].nmi_name
) == 0)
296 : nds32_isr_vectors
[0].nmi_name
);
297 nds32_emit_section_tail_template (symbol_name
);
299 /* Emit warm handler section. */
300 snprintf (section_name
, sizeof (section_name
), ".nds32_wrh");
301 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_wrh");
303 fprintf (asm_out_file
, "\t! ....................................\n");
304 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
305 fprintf (asm_out_file
, "\t.word\t%s\n",
306 (strlen (nds32_isr_vectors
[0].warm_name
) == 0)
308 : nds32_isr_vectors
[0].warm_name
);
309 nds32_emit_section_tail_template (symbol_name
);
311 fprintf (asm_out_file
, "\t! RESET HANDLER CONTENT - END !\n");
314 /* Function for nds32_merge_decl_attributes() and nds32_insert_attributes()
315 to check if there are any conflict isr-specific attributes being set.
317 1. Only 'save_all' or 'partial_save' in the attributes.
318 2. Only 'nested', 'not_nested', or 'nested_ready' in the attributes.
319 3. Only 'interrupt', 'exception', or 'reset' in the attributes. */
321 nds32_check_isr_attrs_conflict (tree func_decl
, tree func_attrs
)
323 int save_all_p
, partial_save_p
;
324 int nested_p
, not_nested_p
, nested_ready_p
;
325 int intr_p
, excp_p
, reset_p
;
327 /* Initialize variables. */
328 save_all_p
= partial_save_p
= 0;
329 nested_p
= not_nested_p
= nested_ready_p
= 0;
330 intr_p
= excp_p
= reset_p
= 0;
332 /* We must check at MOST one attribute to set save-reg. */
333 if (lookup_attribute ("save_all", func_attrs
))
335 if (lookup_attribute ("partial_save", func_attrs
))
338 if ((save_all_p
+ partial_save_p
) > 1)
339 error ("multiple save reg attributes to function %qD", func_decl
);
341 /* We must check at MOST one attribute to set nested-type. */
342 if (lookup_attribute ("nested", func_attrs
))
344 if (lookup_attribute ("not_nested", func_attrs
))
346 if (lookup_attribute ("nested_ready", func_attrs
))
349 if ((nested_p
+ not_nested_p
+ nested_ready_p
) > 1)
350 error ("multiple nested types attributes to function %qD", func_decl
);
352 /* We must check at MOST one attribute to
353 set interrupt/exception/reset. */
354 if (lookup_attribute ("interrupt", func_attrs
))
356 if (lookup_attribute ("exception", func_attrs
))
358 if (lookup_attribute ("reset", func_attrs
))
361 if ((intr_p
+ excp_p
+ reset_p
) > 1)
362 error ("multiple interrupt attributes to function %qD", func_decl
);
365 /* Function to construct isr vectors information array.
366 We DO NOT HAVE TO check if the attributes are valid
367 because those works are supposed to be done on
368 nds32_merge_decl_attributes() and nds32_insert_attributes(). */
370 nds32_construct_isr_vectors_information (tree func_attrs
,
371 const char *func_name
)
373 tree save_all
, partial_save
;
374 tree nested
, not_nested
, nested_ready
;
375 tree intr
, excp
, reset
;
377 save_all
= lookup_attribute ("save_all", func_attrs
);
378 partial_save
= lookup_attribute ("partial_save", func_attrs
);
380 nested
= lookup_attribute ("nested", func_attrs
);
381 not_nested
= lookup_attribute ("not_nested", func_attrs
);
382 nested_ready
= lookup_attribute ("nested_ready", func_attrs
);
384 intr
= lookup_attribute ("interrupt", func_attrs
);
385 excp
= lookup_attribute ("exception", func_attrs
);
386 reset
= lookup_attribute ("reset", func_attrs
);
388 /* If there is no interrupt/exception/reset, we can return immediately. */
389 if (!intr
&& !excp
&& !reset
)
392 /* If we are here, either we have interrupt/exception,
393 or reset attribute. */
398 /* Prepare id list so that we can traverse and set vector id. */
399 id_list
= (intr
) ? (TREE_VALUE (intr
)) : (TREE_VALUE (excp
));
405 unsigned int vector_number_offset
;
407 /* The way to handle interrupt or exception is the same,
408 we just need to take care of actual vector number.
409 For interrupt(0..63), the actual vector number is (9..72).
410 For exception(1..8), the actual vector number is (1..8). */
411 vector_number_offset
= (intr
) ? (9) : (0);
413 /* Pick up each vector id value. */
414 id
= TREE_VALUE (id_list
);
415 /* Add vector_number_offset to get actual vector number. */
416 vector_id
= TREE_INT_CST_LOW (id
) + vector_number_offset
;
418 /* Enable corresponding vector and set function name. */
419 nds32_isr_vectors
[vector_id
].category
= (intr
)
420 ? (NDS32_ISR_INTERRUPT
)
421 : (NDS32_ISR_EXCEPTION
);
422 strcpy (nds32_isr_vectors
[vector_id
].func_name
, func_name
);
424 /* Set register saving scheme. */
426 nds32_isr_vectors
[vector_id
].save_reg
= NDS32_SAVE_ALL
;
427 else if (partial_save
)
428 nds32_isr_vectors
[vector_id
].save_reg
= NDS32_PARTIAL_SAVE
;
430 /* Set nested type. */
432 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NESTED
;
434 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NOT_NESTED
;
435 else if (nested_ready
)
436 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NESTED_READY
;
438 /* Advance to next id. */
439 id_list
= TREE_CHAIN (id_list
);
448 /* Deal with reset attribute. Its vector number is always 0. */
449 nds32_isr_vectors
[0].category
= NDS32_ISR_RESET
;
451 /* Prepare id_list and identify id value so that
452 we can set total number of vectors. */
453 id_list
= TREE_VALUE (reset
);
454 id
= TREE_VALUE (id_list
);
456 /* The total vectors = interrupt + exception numbers + reset.
457 There are 8 exception and 1 reset in nds32 architecture. */
458 nds32_isr_vectors
[0].total_n_vectors
= TREE_INT_CST_LOW (id
) + 8 + 1;
459 strcpy (nds32_isr_vectors
[0].func_name
, func_name
);
461 /* Retrieve nmi and warm function. */
462 nmi
= lookup_attribute ("nmi", func_attrs
);
463 warm
= lookup_attribute ("warm", func_attrs
);
465 if (nmi
!= NULL_TREE
)
470 nmi_func_list
= TREE_VALUE (nmi
);
471 nmi_func
= TREE_VALUE (nmi_func_list
);
473 /* Record nmi function name. */
474 strcpy (nds32_isr_vectors
[0].nmi_name
,
475 IDENTIFIER_POINTER (nmi_func
));
478 if (warm
!= NULL_TREE
)
483 warm_func_list
= TREE_VALUE (warm
);
484 warm_func
= TREE_VALUE (warm_func_list
);
486 /* Record warm function name. */
487 strcpy (nds32_isr_vectors
[0].warm_name
,
488 IDENTIFIER_POINTER (warm_func
));
493 /* A helper function to handle isr stuff at the beginning of asm file. */
495 nds32_asm_file_start_for_isr (void)
499 /* Initialize isr vector information array before compiling functions. */
500 for (i
= 0; i
< NDS32_N_ISR_VECTORS
; i
++)
502 nds32_isr_vectors
[i
].category
= NDS32_ISR_NONE
;
503 strcpy (nds32_isr_vectors
[i
].func_name
, "");
504 nds32_isr_vectors
[i
].save_reg
= NDS32_PARTIAL_SAVE
;
505 nds32_isr_vectors
[i
].nested_type
= NDS32_NOT_NESTED
;
506 nds32_isr_vectors
[i
].total_n_vectors
= 0;
507 strcpy (nds32_isr_vectors
[i
].nmi_name
, "");
508 strcpy (nds32_isr_vectors
[i
].warm_name
, "");
512 /* A helper function to handle isr stuff at the end of asm file. */
514 nds32_asm_file_end_for_isr (void)
518 /* If all the vectors are NDS32_ISR_NONE, we can return immediately. */
519 for (i
= 0; i
< NDS32_N_ISR_VECTORS
; i
++)
520 if (nds32_isr_vectors
[i
].category
!= NDS32_ISR_NONE
)
523 if (i
== NDS32_N_ISR_VECTORS
)
526 /* At least one vector is NOT NDS32_ISR_NONE,
527 we should output isr vector information. */
528 fprintf (asm_out_file
, "\t! ------------------------------------\n");
529 fprintf (asm_out_file
, "\t! The isr vector information:\n");
530 fprintf (asm_out_file
, "\t! ------------------------------------\n");
532 /* Check reset handler first. Its vector number is always 0. */
533 if (nds32_isr_vectors
[0].category
== NDS32_ISR_RESET
)
535 nds32_emit_isr_reset_content ();
536 fprintf (asm_out_file
, "\t! ------------------------------------\n");
539 /* Check other vectors, starting from vector number 1. */
540 for (i
= 1; i
< NDS32_N_ISR_VECTORS
; i
++)
542 if (nds32_isr_vectors
[i
].category
== NDS32_ISR_INTERRUPT
543 || nds32_isr_vectors
[i
].category
== NDS32_ISR_EXCEPTION
)
545 /* Found one vector which is interupt or exception.
546 Output its jmptbl and vector section content. */
547 fprintf (asm_out_file
, "\t! interrupt/exception vector %02d\n", i
);
548 fprintf (asm_out_file
, "\t! ------------------------------------\n");
549 nds32_emit_isr_jmptbl_section (i
);
550 fprintf (asm_out_file
, "\t! ....................................\n");
551 nds32_emit_isr_vector_section (i
);
552 fprintf (asm_out_file
, "\t! ------------------------------------\n");
557 /* Return true if FUNC is a isr function. */
559 nds32_isr_function_p (tree func
)
567 if (TREE_CODE (func
) != FUNCTION_DECL
)
570 attrs
= DECL_ATTRIBUTES (func
);
572 t_intr
= lookup_attribute ("interrupt", attrs
);
573 t_excp
= lookup_attribute ("exception", attrs
);
574 t_reset
= lookup_attribute ("reset", attrs
);
576 return ((t_intr
!= NULL_TREE
)
577 || (t_excp
!= NULL_TREE
)
578 || (t_reset
!= NULL_TREE
));
581 /* ------------------------------------------------------------------------ */