1 /* Subroutines used for ISR of Andes NDS32 cpu for GNU compiler
2 Copyright (C) 2012-2018 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 /* ------------------------------------------------------------------------ */
23 #define IN_TARGET_CODE 1
27 #include "coretypes.h"
32 #include "stringpool.h"
34 #include "diagnostic-core.h"
37 /* ------------------------------------------------------------------------ */
39 /* Refer to nds32.h, there are maximum 73 isr vectors in nds32 architecture.
40 0 for reset handler with __attribute__((reset())),
41 1-8 for exception handler with __attribute__((exception(1,...,8))),
42 and 9-72 for interrupt handler with __attribute__((interrupt(0,...,63))).
43 We use an array to record essential information for each vector. */
44 static struct nds32_isr_info nds32_isr_vectors
[NDS32_N_ISR_VECTORS
];
46 /* ------------------------------------------------------------------------ */
48 /* A helper function to emit section head template. */
50 nds32_emit_section_head_template (char section_name
[],
55 const char *flags_str
;
58 flags_str
= (object_p
) ? "\"a\"" : "\"ax\"";
59 type_str
= (object_p
) ? "@object" : "@function";
61 fprintf (asm_out_file
, "\t.section\t%s, %s\n", section_name
, flags_str
);
62 fprintf (asm_out_file
, "\t.align\t%d\n", align_value
);
63 fprintf (asm_out_file
, "\t.global\t%s\n", symbol_name
);
64 fprintf (asm_out_file
, "\t.type\t%s, %s\n", symbol_name
, type_str
);
65 fprintf (asm_out_file
, "%s:\n", symbol_name
);
68 /* A helper function to emit section tail template. */
70 nds32_emit_section_tail_template (char symbol_name
[])
72 fprintf (asm_out_file
, "\t.size\t%s, .-%s\n", symbol_name
, symbol_name
);
75 /* Function to emit isr jump table section. */
77 nds32_emit_isr_jmptbl_section (int vector_id
)
79 char section_name
[100];
80 char symbol_name
[100];
82 /* Prepare jmptbl section and symbol name. */
83 snprintf (section_name
, sizeof (section_name
),
84 ".nds32_jmptbl.%02d", vector_id
);
85 snprintf (symbol_name
, sizeof (symbol_name
),
86 "_nds32_jmptbl_%02d", vector_id
);
88 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
89 fprintf (asm_out_file
, "\t.word\t%s\n",
90 nds32_isr_vectors
[vector_id
].func_name
);
91 nds32_emit_section_tail_template (symbol_name
);
94 /* Function to emit isr vector section. */
96 nds32_emit_isr_vector_section (int vector_id
)
98 unsigned int vector_number_offset
= 0;
99 const char *c_str
= "CATEGORY";
100 const char *sr_str
= "SR";
101 const char *nt_str
= "NT";
102 const char *vs_str
= "VS";
103 char first_level_handler_name
[100];
104 char section_name
[100];
105 char symbol_name
[100];
107 /* Set the vector number offset so that we can calculate
108 the value that user specifies in the attribute.
109 We also prepare the category string for first level handler name. */
110 switch (nds32_isr_vectors
[vector_id
].category
)
112 case NDS32_ISR_INTERRUPT
:
113 vector_number_offset
= 9;
116 case NDS32_ISR_EXCEPTION
:
117 vector_number_offset
= 0;
121 case NDS32_ISR_RESET
:
122 /* Normally it should not be here. */
127 /* Prepare save reg string for first level handler name. */
128 switch (nds32_isr_vectors
[vector_id
].save_reg
)
133 case NDS32_PARTIAL_SAVE
:
138 /* Prepare nested type string for first level handler name. */
139 switch (nds32_isr_vectors
[vector_id
].nested_type
)
144 case NDS32_NOT_NESTED
:
147 case NDS32_NESTED_READY
:
152 /* Currently we have 4-byte or 16-byte size for each vector.
153 If it is 4-byte, the first level handler name has suffix string "_4b". */
154 vs_str
= (nds32_isr_vector_size
== 4) ? "_4b" : "";
156 /* Now we can create first level handler name. */
157 snprintf (first_level_handler_name
, sizeof (first_level_handler_name
),
158 "_nds32_%s_%s_%s%s", c_str
, sr_str
, nt_str
, vs_str
);
160 /* Prepare vector section and symbol name. */
161 snprintf (section_name
, sizeof (section_name
),
162 ".nds32_vector.%02d", vector_id
);
163 snprintf (symbol_name
, sizeof (symbol_name
),
164 "_nds32_vector_%02d%s", vector_id
, vs_str
);
167 /* Everything is ready. We can start emit vector section content. */
168 nds32_emit_section_head_template (section_name
, symbol_name
,
169 floor_log2 (nds32_isr_vector_size
), false);
171 /* According to the vector size, the instructions in the
172 vector section may be different. */
173 if (nds32_isr_vector_size
== 4)
175 /* This block is for 4-byte vector size.
176 Hardware $VID support is necessary and only one instruction
177 is needed in vector section. */
178 fprintf (asm_out_file
, "\tj\t%s ! jump to first level handler\n",
179 first_level_handler_name
);
183 /* This block is for 16-byte vector size.
184 There is NO hardware $VID so that we need several instructions
185 such as pushing GPRs and preparing software vid at vector section.
186 For pushing GPRs, there are four variations for
187 16-byte vector content and we have to handle each combination.
188 For preparing software vid, note that the vid need to
189 be substracted vector_number_offset. */
190 if (TARGET_REDUCED_REGS
)
192 if (nds32_isr_vectors
[vector_id
].save_reg
== NDS32_SAVE_ALL
)
194 /* Case of reduced set registers and save_all attribute. */
195 fprintf (asm_out_file
, "\t! reduced set regs + save_all\n");
196 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r15, 0xf\n");
197 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r10, 0x0\n");
202 /* Case of reduced set registers and partial_save attribute. */
203 fprintf (asm_out_file
, "\t! reduced set regs + partial_save\n");
204 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r15, 0x2\n");
205 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
210 if (nds32_isr_vectors
[vector_id
].save_reg
== NDS32_SAVE_ALL
)
212 /* Case of full set registers and save_all attribute. */
213 fprintf (asm_out_file
, "\t! full set regs + save_all\n");
214 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r27, 0xf\n");
218 /* Case of full set registers and partial_save attribute. */
219 fprintf (asm_out_file
, "\t! full set regs + partial_save\n");
220 fprintf (asm_out_file
, "\tsmw.adm\t$r15, [$sp], $r27, 0x2\n");
221 fprintf (asm_out_file
, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
225 fprintf (asm_out_file
, "\tmovi\t$r0, %d ! preparing software vid\n",
226 vector_id
- vector_number_offset
);
227 fprintf (asm_out_file
, "\tj\t%s ! jump to first level handler\n",
228 first_level_handler_name
);
231 nds32_emit_section_tail_template (symbol_name
);
234 /* Function to emit isr reset handler content.
235 Including all jmptbl/vector references, jmptbl section,
236 vector section, nmi handler section, and warm handler section. */
238 nds32_emit_isr_reset_content (void)
241 unsigned int total_n_vectors
;
243 char reset_handler_name
[100];
244 char section_name
[100];
245 char symbol_name
[100];
247 total_n_vectors
= nds32_isr_vectors
[0].total_n_vectors
;
248 vs_str
= (nds32_isr_vector_size
== 4) ? "_4b" : "";
250 fprintf (asm_out_file
, "\t! RESET HANDLER CONTENT - BEGIN !\n");
252 /* Create references in .rodata according to total number of vectors. */
253 fprintf (asm_out_file
, "\t.section\t.rodata\n");
254 fprintf (asm_out_file
, "\t.align\t2\n");
256 /* Emit jmptbl references. */
257 fprintf (asm_out_file
, "\t ! references to jmptbl section entries\n");
258 for (i
= 0; i
< total_n_vectors
; i
++)
259 fprintf (asm_out_file
, "\t.word\t_nds32_jmptbl_%02d\n", i
);
261 /* Emit vector references. */
262 fprintf (asm_out_file
, "\t ! references to vector section entries\n");
263 for (i
= 0; i
< total_n_vectors
; i
++)
264 fprintf (asm_out_file
, "\t.word\t_nds32_vector_%02d%s\n", i
, vs_str
);
266 /* Emit jmptbl_00 section. */
267 snprintf (section_name
, sizeof (section_name
), ".nds32_jmptbl.00");
268 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_jmptbl_00");
270 fprintf (asm_out_file
, "\t! ....................................\n");
271 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
272 fprintf (asm_out_file
, "\t.word\t%s\n",
273 nds32_isr_vectors
[0].func_name
);
274 nds32_emit_section_tail_template (symbol_name
);
276 /* Emit vector_00 section. */
277 snprintf (section_name
, sizeof (section_name
), ".nds32_vector.00");
278 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_vector_00%s", vs_str
);
279 snprintf (reset_handler_name
, sizeof (reset_handler_name
),
280 "_nds32_reset%s", vs_str
);
282 fprintf (asm_out_file
, "\t! ....................................\n");
283 nds32_emit_section_head_template (section_name
, symbol_name
,
284 floor_log2 (nds32_isr_vector_size
), false);
285 fprintf (asm_out_file
, "\tj\t%s ! jump to reset handler\n",
287 nds32_emit_section_tail_template (symbol_name
);
289 /* Emit nmi handler section. */
290 snprintf (section_name
, sizeof (section_name
), ".nds32_nmih");
291 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_nmih");
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 (strlen (nds32_isr_vectors
[0].nmi_name
) == 0)
298 : nds32_isr_vectors
[0].nmi_name
);
299 nds32_emit_section_tail_template (symbol_name
);
301 /* Emit warm handler section. */
302 snprintf (section_name
, sizeof (section_name
), ".nds32_wrh");
303 snprintf (symbol_name
, sizeof (symbol_name
), "_nds32_wrh");
305 fprintf (asm_out_file
, "\t! ....................................\n");
306 nds32_emit_section_head_template (section_name
, symbol_name
, 2, true);
307 fprintf (asm_out_file
, "\t.word\t%s\n",
308 (strlen (nds32_isr_vectors
[0].warm_name
) == 0)
310 : nds32_isr_vectors
[0].warm_name
);
311 nds32_emit_section_tail_template (symbol_name
);
313 fprintf (asm_out_file
, "\t! RESET HANDLER CONTENT - END !\n");
316 /* Function for nds32_merge_decl_attributes() and nds32_insert_attributes()
317 to check if there are any conflict isr-specific attributes being set.
319 1. Only 'save_all' or 'partial_save' in the attributes.
320 2. Only 'nested', 'not_nested', or 'nested_ready' in the attributes.
321 3. Only 'interrupt', 'exception', or 'reset' in the attributes. */
323 nds32_check_isr_attrs_conflict (tree func_decl
, tree func_attrs
)
325 int save_all_p
, partial_save_p
;
326 int nested_p
, not_nested_p
, nested_ready_p
;
327 int intr_p
, excp_p
, reset_p
;
329 /* Initialize variables. */
330 save_all_p
= partial_save_p
= 0;
331 nested_p
= not_nested_p
= nested_ready_p
= 0;
332 intr_p
= excp_p
= reset_p
= 0;
334 /* We must check at MOST one attribute to set save-reg. */
335 if (lookup_attribute ("save_all", func_attrs
))
337 if (lookup_attribute ("partial_save", func_attrs
))
340 if ((save_all_p
+ partial_save_p
) > 1)
341 error ("multiple save reg attributes to function %qD", func_decl
);
343 /* We must check at MOST one attribute to set nested-type. */
344 if (lookup_attribute ("nested", func_attrs
))
346 if (lookup_attribute ("not_nested", func_attrs
))
348 if (lookup_attribute ("nested_ready", func_attrs
))
351 if ((nested_p
+ not_nested_p
+ nested_ready_p
) > 1)
352 error ("multiple nested types attributes to function %qD", func_decl
);
354 /* We must check at MOST one attribute to
355 set interrupt/exception/reset. */
356 if (lookup_attribute ("interrupt", func_attrs
))
358 if (lookup_attribute ("exception", func_attrs
))
360 if (lookup_attribute ("reset", func_attrs
))
363 if ((intr_p
+ excp_p
+ reset_p
) > 1)
364 error ("multiple interrupt attributes to function %qD", func_decl
);
367 /* Function to construct isr vectors information array.
368 We DO NOT HAVE TO check if the attributes are valid
369 because those works are supposed to be done on
370 nds32_merge_decl_attributes() and nds32_insert_attributes(). */
372 nds32_construct_isr_vectors_information (tree func_attrs
,
373 const char *func_name
)
375 tree save_all
, partial_save
;
376 tree nested
, not_nested
, nested_ready
;
377 tree intr
, excp
, reset
;
379 save_all
= lookup_attribute ("save_all", func_attrs
);
380 partial_save
= lookup_attribute ("partial_save", func_attrs
);
382 nested
= lookup_attribute ("nested", func_attrs
);
383 not_nested
= lookup_attribute ("not_nested", func_attrs
);
384 nested_ready
= lookup_attribute ("nested_ready", func_attrs
);
386 intr
= lookup_attribute ("interrupt", func_attrs
);
387 excp
= lookup_attribute ("exception", func_attrs
);
388 reset
= lookup_attribute ("reset", func_attrs
);
390 /* If there is no interrupt/exception/reset, we can return immediately. */
391 if (!intr
&& !excp
&& !reset
)
394 /* If we are here, either we have interrupt/exception,
395 or reset attribute. */
400 /* Prepare id list so that we can traverse and set vector id. */
401 id_list
= (intr
) ? (TREE_VALUE (intr
)) : (TREE_VALUE (excp
));
407 unsigned int vector_number_offset
;
409 /* The way to handle interrupt or exception is the same,
410 we just need to take care of actual vector number.
411 For interrupt(0..63), the actual vector number is (9..72).
412 For exception(1..8), the actual vector number is (1..8). */
413 vector_number_offset
= (intr
) ? (9) : (0);
415 /* Pick up each vector id value. */
416 id
= TREE_VALUE (id_list
);
417 /* Add vector_number_offset to get actual vector number. */
418 vector_id
= TREE_INT_CST_LOW (id
) + vector_number_offset
;
420 /* Enable corresponding vector and set function name. */
421 nds32_isr_vectors
[vector_id
].category
= (intr
)
422 ? (NDS32_ISR_INTERRUPT
)
423 : (NDS32_ISR_EXCEPTION
);
424 strcpy (nds32_isr_vectors
[vector_id
].func_name
, func_name
);
426 /* Set register saving scheme. */
428 nds32_isr_vectors
[vector_id
].save_reg
= NDS32_SAVE_ALL
;
429 else if (partial_save
)
430 nds32_isr_vectors
[vector_id
].save_reg
= NDS32_PARTIAL_SAVE
;
432 /* Set nested type. */
434 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NESTED
;
436 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NOT_NESTED
;
437 else if (nested_ready
)
438 nds32_isr_vectors
[vector_id
].nested_type
= NDS32_NESTED_READY
;
440 /* Advance to next id. */
441 id_list
= TREE_CHAIN (id_list
);
450 /* Deal with reset attribute. Its vector number is always 0. */
451 nds32_isr_vectors
[0].category
= NDS32_ISR_RESET
;
453 /* Prepare id_list and identify id value so that
454 we can set total number of vectors. */
455 id_list
= TREE_VALUE (reset
);
456 id
= TREE_VALUE (id_list
);
458 /* The total vectors = interrupt + exception numbers + reset.
459 There are 8 exception and 1 reset in nds32 architecture. */
460 nds32_isr_vectors
[0].total_n_vectors
= TREE_INT_CST_LOW (id
) + 8 + 1;
461 strcpy (nds32_isr_vectors
[0].func_name
, func_name
);
463 /* Retrieve nmi and warm function. */
464 nmi
= lookup_attribute ("nmi", func_attrs
);
465 warm
= lookup_attribute ("warm", func_attrs
);
467 if (nmi
!= NULL_TREE
)
472 nmi_func_list
= TREE_VALUE (nmi
);
473 nmi_func
= TREE_VALUE (nmi_func_list
);
475 /* Record nmi function name. */
476 strcpy (nds32_isr_vectors
[0].nmi_name
,
477 IDENTIFIER_POINTER (nmi_func
));
480 if (warm
!= NULL_TREE
)
485 warm_func_list
= TREE_VALUE (warm
);
486 warm_func
= TREE_VALUE (warm_func_list
);
488 /* Record warm function name. */
489 strcpy (nds32_isr_vectors
[0].warm_name
,
490 IDENTIFIER_POINTER (warm_func
));
495 /* A helper function to handle isr stuff at the beginning of asm file. */
497 nds32_asm_file_start_for_isr (void)
501 /* Initialize isr vector information array before compiling functions. */
502 for (i
= 0; i
< NDS32_N_ISR_VECTORS
; i
++)
504 nds32_isr_vectors
[i
].category
= NDS32_ISR_NONE
;
505 strcpy (nds32_isr_vectors
[i
].func_name
, "");
506 nds32_isr_vectors
[i
].save_reg
= NDS32_PARTIAL_SAVE
;
507 nds32_isr_vectors
[i
].nested_type
= NDS32_NOT_NESTED
;
508 nds32_isr_vectors
[i
].total_n_vectors
= 0;
509 strcpy (nds32_isr_vectors
[i
].nmi_name
, "");
510 strcpy (nds32_isr_vectors
[i
].warm_name
, "");
514 /* A helper function to handle isr stuff at the end of asm file. */
516 nds32_asm_file_end_for_isr (void)
520 /* If all the vectors are NDS32_ISR_NONE, we can return immediately. */
521 for (i
= 0; i
< NDS32_N_ISR_VECTORS
; i
++)
522 if (nds32_isr_vectors
[i
].category
!= NDS32_ISR_NONE
)
525 if (i
== NDS32_N_ISR_VECTORS
)
528 /* At least one vector is NOT NDS32_ISR_NONE,
529 we should output isr vector information. */
530 fprintf (asm_out_file
, "\t! ------------------------------------\n");
531 fprintf (asm_out_file
, "\t! The isr vector information:\n");
532 fprintf (asm_out_file
, "\t! ------------------------------------\n");
534 /* Check reset handler first. Its vector number is always 0. */
535 if (nds32_isr_vectors
[0].category
== NDS32_ISR_RESET
)
537 nds32_emit_isr_reset_content ();
538 fprintf (asm_out_file
, "\t! ------------------------------------\n");
541 /* Check other vectors, starting from vector number 1. */
542 for (i
= 1; i
< NDS32_N_ISR_VECTORS
; i
++)
544 if (nds32_isr_vectors
[i
].category
== NDS32_ISR_INTERRUPT
545 || nds32_isr_vectors
[i
].category
== NDS32_ISR_EXCEPTION
)
547 /* Found one vector which is interupt or exception.
548 Output its jmptbl and vector section content. */
549 fprintf (asm_out_file
, "\t! interrupt/exception vector %02d\n", i
);
550 fprintf (asm_out_file
, "\t! ------------------------------------\n");
551 nds32_emit_isr_jmptbl_section (i
);
552 fprintf (asm_out_file
, "\t! ....................................\n");
553 nds32_emit_isr_vector_section (i
);
554 fprintf (asm_out_file
, "\t! ------------------------------------\n");
559 /* Return true if FUNC is a isr function. */
561 nds32_isr_function_p (tree func
)
569 if (TREE_CODE (func
) != FUNCTION_DECL
)
572 attrs
= DECL_ATTRIBUTES (func
);
574 t_intr
= lookup_attribute ("interrupt", attrs
);
575 t_excp
= lookup_attribute ("exception", attrs
);
576 t_reset
= lookup_attribute ("reset", attrs
);
578 return ((t_intr
!= NULL_TREE
)
579 || (t_excp
!= NULL_TREE
)
580 || (t_reset
!= NULL_TREE
));
583 /* ------------------------------------------------------------------------ */