]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/nds32/nds32-isr.c
[NDS32] Add a function to indentify if FUNC is an interrupt service routine.
[thirdparty/gcc.git] / gcc / config / nds32 / nds32-isr.c
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.
4
5 This file is part of GCC.
6
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.
11
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.
16
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/>. */
20
21 /* ------------------------------------------------------------------------ */
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "tree.h"
28 #include "stor-layout.h"
29 #include "varasm.h"
30 #include "calls.h"
31 #include "rtl.h"
32 #include "regs.h"
33 #include "hard-reg-set.h"
34 #include "insn-config.h" /* Required by recog.h. */
35 #include "conditions.h"
36 #include "output.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(). */
40 #include "flags.h"
41 #include "function.h"
42 #include "expr.h"
43 #include "recog.h"
44 #include "diagnostic-core.h"
45 #include "df.h"
46 #include "tm_p.h"
47 #include "tm-constrs.h"
48 #include "optabs.h" /* For GEN_FCN. */
49 #include "target.h"
50 #include "target-def.h"
51 #include "langhooks.h" /* For add_builtin_function(). */
52 #include "ggc.h"
53 #include "builtins.h"
54
55 /* ------------------------------------------------------------------------ */
56
57 /* Refer to nds32.h, there are maximum 73 isr vectors in nds32 architecture.
58 0 for reset handler with __attribute__((reset())),
59 1-8 for exception handler with __attribute__((exception(1,...,8))),
60 and 9-72 for interrupt handler with __attribute__((interrupt(0,...,63))).
61 We use an array to record essential information for each vector. */
62 static struct nds32_isr_info nds32_isr_vectors[NDS32_N_ISR_VECTORS];
63
64 /* ------------------------------------------------------------------------ */
65
66 /* A helper function to emit section head template. */
67 static void
68 nds32_emit_section_head_template (char section_name[],
69 char symbol_name[],
70 int align_value,
71 bool object_p)
72 {
73 const char *flags_str;
74 const char *type_str;
75
76 flags_str = (object_p) ? "\"a\"" : "\"ax\"";
77 type_str = (object_p) ? "@object" : "@function";
78
79 fprintf (asm_out_file, "\t.section\t%s, %s\n", section_name, flags_str);
80 fprintf (asm_out_file, "\t.align\t%d\n", align_value);
81 fprintf (asm_out_file, "\t.global\t%s\n", symbol_name);
82 fprintf (asm_out_file, "\t.type\t%s, %s\n", symbol_name, type_str);
83 fprintf (asm_out_file, "%s:\n", symbol_name);
84 }
85
86 /* A helper function to emit section tail template. */
87 static void
88 nds32_emit_section_tail_template (char symbol_name[])
89 {
90 fprintf (asm_out_file, "\t.size\t%s, .-%s\n", symbol_name, symbol_name);
91 }
92
93 /* Function to emit isr jump table section. */
94 static void
95 nds32_emit_isr_jmptbl_section (int vector_id)
96 {
97 char section_name[100];
98 char symbol_name[100];
99
100 /* Prepare jmptbl section and symbol name. */
101 snprintf (section_name, sizeof (section_name),
102 ".nds32_jmptbl.%02d", vector_id);
103 snprintf (symbol_name, sizeof (symbol_name),
104 "_nds32_jmptbl_%02d", vector_id);
105
106 nds32_emit_section_head_template (section_name, symbol_name, 2, true);
107 fprintf (asm_out_file, "\t.word\t%s\n",
108 nds32_isr_vectors[vector_id].func_name);
109 nds32_emit_section_tail_template (symbol_name);
110 }
111
112 /* Function to emit isr vector section. */
113 static void
114 nds32_emit_isr_vector_section (int vector_id)
115 {
116 unsigned int vector_number_offset = 0;
117 const char *c_str = "CATEGORY";
118 const char *sr_str = "SR";
119 const char *nt_str = "NT";
120 const char *vs_str = "VS";
121 char first_level_handler_name[100];
122 char section_name[100];
123 char symbol_name[100];
124
125 /* Set the vector number offset so that we can calculate
126 the value that user specifies in the attribute.
127 We also prepare the category string for first level handler name. */
128 switch (nds32_isr_vectors[vector_id].category)
129 {
130 case NDS32_ISR_INTERRUPT:
131 vector_number_offset = 9;
132 c_str = "i";
133 break;
134 case NDS32_ISR_EXCEPTION:
135 vector_number_offset = 0;
136 c_str = "e";
137 break;
138 case NDS32_ISR_NONE:
139 case NDS32_ISR_RESET:
140 /* Normally it should not be here. */
141 gcc_unreachable ();
142 break;
143 }
144
145 /* Prepare save reg string for first level handler name. */
146 switch (nds32_isr_vectors[vector_id].save_reg)
147 {
148 case NDS32_SAVE_ALL:
149 sr_str = "sa";
150 break;
151 case NDS32_PARTIAL_SAVE:
152 sr_str = "ps";
153 break;
154 }
155
156 /* Prepare nested type string for first level handler name. */
157 switch (nds32_isr_vectors[vector_id].nested_type)
158 {
159 case NDS32_NESTED:
160 nt_str = "ns";
161 break;
162 case NDS32_NOT_NESTED:
163 nt_str = "nn";
164 break;
165 case NDS32_NESTED_READY:
166 nt_str = "nr";
167 break;
168 }
169
170 /* Currently we have 4-byte or 16-byte size for each vector.
171 If it is 4-byte, the first level handler name has suffix string "_4b". */
172 vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
173
174 /* Now we can create first level handler name. */
175 snprintf (first_level_handler_name, sizeof (first_level_handler_name),
176 "_nds32_%s_%s_%s%s", c_str, sr_str, nt_str, vs_str);
177
178 /* Prepare vector section and symbol name. */
179 snprintf (section_name, sizeof (section_name),
180 ".nds32_vector.%02d", vector_id);
181 snprintf (symbol_name, sizeof (symbol_name),
182 "_nds32_vector_%02d%s", vector_id, vs_str);
183
184
185 /* Everything is ready. We can start emit vector section content. */
186 nds32_emit_section_head_template (section_name, symbol_name,
187 floor_log2 (nds32_isr_vector_size), false);
188
189 /* According to the vector size, the instructions in the
190 vector section may be different. */
191 if (nds32_isr_vector_size == 4)
192 {
193 /* This block is for 4-byte vector size.
194 Hardware $VID support is necessary and only one instruction
195 is needed in vector section. */
196 fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n",
197 first_level_handler_name);
198 }
199 else
200 {
201 /* This block is for 16-byte vector size.
202 There is NO hardware $VID so that we need several instructions
203 such as pushing GPRs and preparing software vid at vector section.
204 For pushing GPRs, there are four variations for
205 16-byte vector content and we have to handle each combination.
206 For preparing software vid, note that the vid need to
207 be substracted vector_number_offset. */
208 if (TARGET_REDUCED_REGS)
209 {
210 if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
211 {
212 /* Case of reduced set registers and save_all attribute. */
213 fprintf (asm_out_file, "\t! reduced set regs + save_all\n");
214 fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0xf\n");
215 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r10, 0x0\n");
216
217 }
218 else
219 {
220 /* Case of reduced set registers and partial_save attribute. */
221 fprintf (asm_out_file, "\t! reduced set regs + partial_save\n");
222 fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0x2\n");
223 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
224 }
225 }
226 else
227 {
228 if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
229 {
230 /* Case of full set registers and save_all attribute. */
231 fprintf (asm_out_file, "\t! full set regs + save_all\n");
232 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r27, 0xf\n");
233 }
234 else
235 {
236 /* Case of full set registers and partial_save attribute. */
237 fprintf (asm_out_file, "\t! full set regs + partial_save\n");
238 fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r27, 0x2\n");
239 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n");
240 }
241 }
242
243 fprintf (asm_out_file, "\tmovi\t$r0, %d ! preparing software vid\n",
244 vector_id - vector_number_offset);
245 fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n",
246 first_level_handler_name);
247 }
248
249 nds32_emit_section_tail_template (symbol_name);
250 }
251
252 /* Function to emit isr reset handler content.
253 Including all jmptbl/vector references, jmptbl section,
254 vector section, nmi handler section, and warm handler section. */
255 static void
256 nds32_emit_isr_reset_content (void)
257 {
258 unsigned int i;
259 unsigned int total_n_vectors;
260 const char *vs_str;
261 char reset_handler_name[100];
262 char section_name[100];
263 char symbol_name[100];
264
265 total_n_vectors = nds32_isr_vectors[0].total_n_vectors;
266 vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
267
268 fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - BEGIN !\n");
269
270 /* Create references in .rodata according to total number of vectors. */
271 fprintf (asm_out_file, "\t.section\t.rodata\n");
272 fprintf (asm_out_file, "\t.align\t2\n");
273
274 /* Emit jmptbl references. */
275 fprintf (asm_out_file, "\t ! references to jmptbl section entries\n");
276 for (i = 0; i < total_n_vectors; i++)
277 fprintf (asm_out_file, "\t.word\t_nds32_jmptbl_%02d\n", i);
278
279 /* Emit vector references. */
280 fprintf (asm_out_file, "\t ! references to vector section entries\n");
281 for (i = 0; i < total_n_vectors; i++)
282 fprintf (asm_out_file, "\t.word\t_nds32_vector_%02d%s\n", i, vs_str);
283
284 /* Emit jmptbl_00 section. */
285 snprintf (section_name, sizeof (section_name), ".nds32_jmptbl.00");
286 snprintf (symbol_name, sizeof (symbol_name), "_nds32_jmptbl_00");
287
288 fprintf (asm_out_file, "\t! ....................................\n");
289 nds32_emit_section_head_template (section_name, symbol_name, 2, true);
290 fprintf (asm_out_file, "\t.word\t%s\n",
291 nds32_isr_vectors[0].func_name);
292 nds32_emit_section_tail_template (symbol_name);
293
294 /* Emit vector_00 section. */
295 snprintf (section_name, sizeof (section_name), ".nds32_vector.00");
296 snprintf (symbol_name, sizeof (symbol_name), "_nds32_vector_00%s", vs_str);
297 snprintf (reset_handler_name, sizeof (reset_handler_name),
298 "_nds32_reset%s", vs_str);
299
300 fprintf (asm_out_file, "\t! ....................................\n");
301 nds32_emit_section_head_template (section_name, symbol_name,
302 floor_log2 (nds32_isr_vector_size), false);
303 fprintf (asm_out_file, "\tj\t%s ! jump to reset handler\n",
304 reset_handler_name);
305 nds32_emit_section_tail_template (symbol_name);
306
307 /* Emit nmi handler section. */
308 snprintf (section_name, sizeof (section_name), ".nds32_nmih");
309 snprintf (symbol_name, sizeof (symbol_name), "_nds32_nmih");
310
311 fprintf (asm_out_file, "\t! ....................................\n");
312 nds32_emit_section_head_template (section_name, symbol_name, 2, true);
313 fprintf (asm_out_file, "\t.word\t%s\n",
314 (strlen (nds32_isr_vectors[0].nmi_name) == 0)
315 ? "0"
316 : nds32_isr_vectors[0].nmi_name);
317 nds32_emit_section_tail_template (symbol_name);
318
319 /* Emit warm handler section. */
320 snprintf (section_name, sizeof (section_name), ".nds32_wrh");
321 snprintf (symbol_name, sizeof (symbol_name), "_nds32_wrh");
322
323 fprintf (asm_out_file, "\t! ....................................\n");
324 nds32_emit_section_head_template (section_name, symbol_name, 2, true);
325 fprintf (asm_out_file, "\t.word\t%s\n",
326 (strlen (nds32_isr_vectors[0].warm_name) == 0)
327 ? "0"
328 : nds32_isr_vectors[0].warm_name);
329 nds32_emit_section_tail_template (symbol_name);
330
331 fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - END !\n");
332 }
333
334 /* Function for nds32_merge_decl_attributes() and nds32_insert_attributes()
335 to check if there are any conflict isr-specific attributes being set.
336 We need to check:
337 1. Only 'save_all' or 'partial_save' in the attributes.
338 2. Only 'nested', 'not_nested', or 'nested_ready' in the attributes.
339 3. Only 'interrupt', 'exception', or 'reset' in the attributes. */
340 void
341 nds32_check_isr_attrs_conflict (tree func_decl, tree func_attrs)
342 {
343 int save_all_p, partial_save_p;
344 int nested_p, not_nested_p, nested_ready_p;
345 int intr_p, excp_p, reset_p;
346
347 /* Initialize variables. */
348 save_all_p = partial_save_p = 0;
349 nested_p = not_nested_p = nested_ready_p = 0;
350 intr_p = excp_p = reset_p = 0;
351
352 /* We must check at MOST one attribute to set save-reg. */
353 if (lookup_attribute ("save_all", func_attrs))
354 save_all_p = 1;
355 if (lookup_attribute ("partial_save", func_attrs))
356 partial_save_p = 1;
357
358 if ((save_all_p + partial_save_p) > 1)
359 error ("multiple save reg attributes to function %qD", func_decl);
360
361 /* We must check at MOST one attribute to set nested-type. */
362 if (lookup_attribute ("nested", func_attrs))
363 nested_p = 1;
364 if (lookup_attribute ("not_nested", func_attrs))
365 not_nested_p = 1;
366 if (lookup_attribute ("nested_ready", func_attrs))
367 nested_ready_p = 1;
368
369 if ((nested_p + not_nested_p + nested_ready_p) > 1)
370 error ("multiple nested types attributes to function %qD", func_decl);
371
372 /* We must check at MOST one attribute to
373 set interrupt/exception/reset. */
374 if (lookup_attribute ("interrupt", func_attrs))
375 intr_p = 1;
376 if (lookup_attribute ("exception", func_attrs))
377 excp_p = 1;
378 if (lookup_attribute ("reset", func_attrs))
379 reset_p = 1;
380
381 if ((intr_p + excp_p + reset_p) > 1)
382 error ("multiple interrupt attributes to function %qD", func_decl);
383 }
384
385 /* Function to construct isr vectors information array.
386 We DO NOT HAVE TO check if the attributes are valid
387 because those works are supposed to be done on
388 nds32_merge_decl_attributes() and nds32_insert_attributes(). */
389 void
390 nds32_construct_isr_vectors_information (tree func_attrs,
391 const char *func_name)
392 {
393 tree save_all, partial_save;
394 tree nested, not_nested, nested_ready;
395 tree intr, excp, reset;
396
397 save_all = lookup_attribute ("save_all", func_attrs);
398 partial_save = lookup_attribute ("partial_save", func_attrs);
399
400 nested = lookup_attribute ("nested", func_attrs);
401 not_nested = lookup_attribute ("not_nested", func_attrs);
402 nested_ready = lookup_attribute ("nested_ready", func_attrs);
403
404 intr = lookup_attribute ("interrupt", func_attrs);
405 excp = lookup_attribute ("exception", func_attrs);
406 reset = lookup_attribute ("reset", func_attrs);
407
408 /* If there is no interrupt/exception/reset, we can return immediately. */
409 if (!intr && !excp && !reset)
410 return;
411
412 /* If we are here, either we have interrupt/exception,
413 or reset attribute. */
414 if (intr || excp)
415 {
416 tree id_list;
417
418 /* Prepare id list so that we can traverse and set vector id. */
419 id_list = (intr) ? (TREE_VALUE (intr)) : (TREE_VALUE (excp));
420
421 while (id_list)
422 {
423 tree id;
424 int vector_id;
425 unsigned int vector_number_offset;
426
427 /* The way to handle interrupt or exception is the same,
428 we just need to take care of actual vector number.
429 For interrupt(0..63), the actual vector number is (9..72).
430 For exception(1..8), the actual vector number is (1..8). */
431 vector_number_offset = (intr) ? (9) : (0);
432
433 /* Pick up each vector id value. */
434 id = TREE_VALUE (id_list);
435 /* Add vector_number_offset to get actual vector number. */
436 vector_id = TREE_INT_CST_LOW (id) + vector_number_offset;
437
438 /* Enable corresponding vector and set function name. */
439 nds32_isr_vectors[vector_id].category = (intr)
440 ? (NDS32_ISR_INTERRUPT)
441 : (NDS32_ISR_EXCEPTION);
442 strcpy (nds32_isr_vectors[vector_id].func_name, func_name);
443
444 /* Set register saving scheme. */
445 if (save_all)
446 nds32_isr_vectors[vector_id].save_reg = NDS32_SAVE_ALL;
447 else if (partial_save)
448 nds32_isr_vectors[vector_id].save_reg = NDS32_PARTIAL_SAVE;
449
450 /* Set nested type. */
451 if (nested)
452 nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED;
453 else if (not_nested)
454 nds32_isr_vectors[vector_id].nested_type = NDS32_NOT_NESTED;
455 else if (nested_ready)
456 nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED_READY;
457
458 /* Advance to next id. */
459 id_list = TREE_CHAIN (id_list);
460 }
461 }
462 else
463 {
464 tree id_list;
465 tree id;
466 tree nmi, warm;
467
468 /* Deal with reset attribute. Its vector number is always 0. */
469 nds32_isr_vectors[0].category = NDS32_ISR_RESET;
470
471 /* Prepare id_list and identify id value so that
472 we can set total number of vectors. */
473 id_list = TREE_VALUE (reset);
474 id = TREE_VALUE (id_list);
475
476 /* The total vectors = interrupt + exception numbers + reset.
477 There are 8 exception and 1 reset in nds32 architecture. */
478 nds32_isr_vectors[0].total_n_vectors = TREE_INT_CST_LOW (id) + 8 + 1;
479 strcpy (nds32_isr_vectors[0].func_name, func_name);
480
481 /* Retrieve nmi and warm function. */
482 nmi = lookup_attribute ("nmi", func_attrs);
483 warm = lookup_attribute ("warm", func_attrs);
484
485 if (nmi != NULL_TREE)
486 {
487 tree nmi_func_list;
488 tree nmi_func;
489
490 nmi_func_list = TREE_VALUE (nmi);
491 nmi_func = TREE_VALUE (nmi_func_list);
492
493 /* Record nmi function name. */
494 strcpy (nds32_isr_vectors[0].nmi_name,
495 IDENTIFIER_POINTER (nmi_func));
496 }
497
498 if (warm != NULL_TREE)
499 {
500 tree warm_func_list;
501 tree warm_func;
502
503 warm_func_list = TREE_VALUE (warm);
504 warm_func = TREE_VALUE (warm_func_list);
505
506 /* Record warm function name. */
507 strcpy (nds32_isr_vectors[0].warm_name,
508 IDENTIFIER_POINTER (warm_func));
509 }
510 }
511 }
512
513 /* A helper function to handle isr stuff at the beginning of asm file. */
514 void
515 nds32_asm_file_start_for_isr (void)
516 {
517 int i;
518
519 /* Initialize isr vector information array before compiling functions. */
520 for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
521 {
522 nds32_isr_vectors[i].category = NDS32_ISR_NONE;
523 strcpy (nds32_isr_vectors[i].func_name, "");
524 nds32_isr_vectors[i].save_reg = NDS32_PARTIAL_SAVE;
525 nds32_isr_vectors[i].nested_type = NDS32_NOT_NESTED;
526 nds32_isr_vectors[i].total_n_vectors = 0;
527 strcpy (nds32_isr_vectors[i].nmi_name, "");
528 strcpy (nds32_isr_vectors[i].warm_name, "");
529 }
530 }
531
532 /* A helper function to handle isr stuff at the end of asm file. */
533 void
534 nds32_asm_file_end_for_isr (void)
535 {
536 int i;
537
538 /* If all the vectors are NDS32_ISR_NONE, we can return immediately. */
539 for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
540 if (nds32_isr_vectors[i].category != NDS32_ISR_NONE)
541 break;
542
543 if (i == NDS32_N_ISR_VECTORS)
544 return;
545
546 /* At least one vector is NOT NDS32_ISR_NONE,
547 we should output isr vector information. */
548 fprintf (asm_out_file, "\t! ------------------------------------\n");
549 fprintf (asm_out_file, "\t! The isr vector information:\n");
550 fprintf (asm_out_file, "\t! ------------------------------------\n");
551
552 /* Check reset handler first. Its vector number is always 0. */
553 if (nds32_isr_vectors[0].category == NDS32_ISR_RESET)
554 {
555 nds32_emit_isr_reset_content ();
556 fprintf (asm_out_file, "\t! ------------------------------------\n");
557 }
558
559 /* Check other vectors, starting from vector number 1. */
560 for (i = 1; i < NDS32_N_ISR_VECTORS; i++)
561 {
562 if (nds32_isr_vectors[i].category == NDS32_ISR_INTERRUPT
563 || nds32_isr_vectors[i].category == NDS32_ISR_EXCEPTION)
564 {
565 /* Found one vector which is interupt or exception.
566 Output its jmptbl and vector section content. */
567 fprintf (asm_out_file, "\t! interrupt/exception vector %02d\n", i);
568 fprintf (asm_out_file, "\t! ------------------------------------\n");
569 nds32_emit_isr_jmptbl_section (i);
570 fprintf (asm_out_file, "\t! ....................................\n");
571 nds32_emit_isr_vector_section (i);
572 fprintf (asm_out_file, "\t! ------------------------------------\n");
573 }
574 }
575 }
576
577 /* Return true if FUNC is a isr function. */
578 bool
579 nds32_isr_function_p (tree func)
580 {
581 tree t_intr;
582 tree t_excp;
583 tree t_reset;
584
585 tree attrs;
586
587 if (TREE_CODE (func) != FUNCTION_DECL)
588 abort ();
589
590 attrs = DECL_ATTRIBUTES (func);
591
592 t_intr = lookup_attribute ("interrupt", attrs);
593 t_excp = lookup_attribute ("exception", attrs);
594 t_reset = lookup_attribute ("reset", attrs);
595
596 return ((t_intr != NULL_TREE)
597 || (t_excp != NULL_TREE)
598 || (t_reset != NULL_TREE));
599 }
600
601 /* ------------------------------------------------------------------------ */