]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/nds32/nds32-isr.c
function.h: Flatten file.
[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 "hashtab.h"
42 #include "hash-set.h"
43 #include "vec.h"
44 #include "machmode.h"
45 #include "input.h"
46 #include "function.h"
47 #include "expr.h"
48 #include "recog.h"
49 #include "diagnostic-core.h"
50 #include "df.h"
51 #include "tm_p.h"
52 #include "tm-constrs.h"
53 #include "optabs.h" /* For GEN_FCN. */
54 #include "target.h"
55 #include "target-def.h"
56 #include "langhooks.h" /* For add_builtin_function(). */
57 #include "ggc.h"
58 #include "builtins.h"
59
60 /* ------------------------------------------------------------------------ */
61
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];
68
69 /* ------------------------------------------------------------------------ */
70
71 /* A helper function to emit section head template. */
72 static void
73 nds32_emit_section_head_template (char section_name[],
74 char symbol_name[],
75 int align_value,
76 bool object_p)
77 {
78 const char *flags_str;
79 const char *type_str;
80
81 flags_str = (object_p) ? "\"a\"" : "\"ax\"";
82 type_str = (object_p) ? "@object" : "@function";
83
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);
89 }
90
91 /* A helper function to emit section tail template. */
92 static void
93 nds32_emit_section_tail_template (char symbol_name[])
94 {
95 fprintf (asm_out_file, "\t.size\t%s, .-%s\n", symbol_name, symbol_name);
96 }
97
98 /* Function to emit isr jump table section. */
99 static void
100 nds32_emit_isr_jmptbl_section (int vector_id)
101 {
102 char section_name[100];
103 char symbol_name[100];
104
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);
110
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);
115 }
116
117 /* Function to emit isr vector section. */
118 static void
119 nds32_emit_isr_vector_section (int vector_id)
120 {
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];
129
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)
134 {
135 case NDS32_ISR_INTERRUPT:
136 vector_number_offset = 9;
137 c_str = "i";
138 break;
139 case NDS32_ISR_EXCEPTION:
140 vector_number_offset = 0;
141 c_str = "e";
142 break;
143 case NDS32_ISR_NONE:
144 case NDS32_ISR_RESET:
145 /* Normally it should not be here. */
146 gcc_unreachable ();
147 break;
148 }
149
150 /* Prepare save reg string for first level handler name. */
151 switch (nds32_isr_vectors[vector_id].save_reg)
152 {
153 case NDS32_SAVE_ALL:
154 sr_str = "sa";
155 break;
156 case NDS32_PARTIAL_SAVE:
157 sr_str = "ps";
158 break;
159 }
160
161 /* Prepare nested type string for first level handler name. */
162 switch (nds32_isr_vectors[vector_id].nested_type)
163 {
164 case NDS32_NESTED:
165 nt_str = "ns";
166 break;
167 case NDS32_NOT_NESTED:
168 nt_str = "nn";
169 break;
170 case NDS32_NESTED_READY:
171 nt_str = "nr";
172 break;
173 }
174
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" : "";
178
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);
182
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);
188
189
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);
193
194 /* According to the vector size, the instructions in the
195 vector section may be different. */
196 if (nds32_isr_vector_size == 4)
197 {
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);
203 }
204 else
205 {
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)
214 {
215 if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
216 {
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");
221
222 }
223 else
224 {
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");
229 }
230 }
231 else
232 {
233 if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
234 {
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");
238 }
239 else
240 {
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");
245 }
246 }
247
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);
252 }
253
254 nds32_emit_section_tail_template (symbol_name);
255 }
256
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. */
260 static void
261 nds32_emit_isr_reset_content (void)
262 {
263 unsigned int i;
264 unsigned int total_n_vectors;
265 const char *vs_str;
266 char reset_handler_name[100];
267 char section_name[100];
268 char symbol_name[100];
269
270 total_n_vectors = nds32_isr_vectors[0].total_n_vectors;
271 vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
272
273 fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - BEGIN !\n");
274
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");
278
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);
283
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);
288
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");
292
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);
298
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);
304
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",
309 reset_handler_name);
310 nds32_emit_section_tail_template (symbol_name);
311
312 /* Emit nmi handler section. */
313 snprintf (section_name, sizeof (section_name), ".nds32_nmih");
314 snprintf (symbol_name, sizeof (symbol_name), "_nds32_nmih");
315
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)
320 ? "0"
321 : nds32_isr_vectors[0].nmi_name);
322 nds32_emit_section_tail_template (symbol_name);
323
324 /* Emit warm handler section. */
325 snprintf (section_name, sizeof (section_name), ".nds32_wrh");
326 snprintf (symbol_name, sizeof (symbol_name), "_nds32_wrh");
327
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)
332 ? "0"
333 : nds32_isr_vectors[0].warm_name);
334 nds32_emit_section_tail_template (symbol_name);
335
336 fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - END !\n");
337 }
338
339 /* Function for nds32_merge_decl_attributes() and nds32_insert_attributes()
340 to check if there are any conflict isr-specific attributes being set.
341 We need to check:
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. */
345 void
346 nds32_check_isr_attrs_conflict (tree func_decl, tree func_attrs)
347 {
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;
351
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;
356
357 /* We must check at MOST one attribute to set save-reg. */
358 if (lookup_attribute ("save_all", func_attrs))
359 save_all_p = 1;
360 if (lookup_attribute ("partial_save", func_attrs))
361 partial_save_p = 1;
362
363 if ((save_all_p + partial_save_p) > 1)
364 error ("multiple save reg attributes to function %qD", func_decl);
365
366 /* We must check at MOST one attribute to set nested-type. */
367 if (lookup_attribute ("nested", func_attrs))
368 nested_p = 1;
369 if (lookup_attribute ("not_nested", func_attrs))
370 not_nested_p = 1;
371 if (lookup_attribute ("nested_ready", func_attrs))
372 nested_ready_p = 1;
373
374 if ((nested_p + not_nested_p + nested_ready_p) > 1)
375 error ("multiple nested types attributes to function %qD", func_decl);
376
377 /* We must check at MOST one attribute to
378 set interrupt/exception/reset. */
379 if (lookup_attribute ("interrupt", func_attrs))
380 intr_p = 1;
381 if (lookup_attribute ("exception", func_attrs))
382 excp_p = 1;
383 if (lookup_attribute ("reset", func_attrs))
384 reset_p = 1;
385
386 if ((intr_p + excp_p + reset_p) > 1)
387 error ("multiple interrupt attributes to function %qD", func_decl);
388 }
389
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(). */
394 void
395 nds32_construct_isr_vectors_information (tree func_attrs,
396 const char *func_name)
397 {
398 tree save_all, partial_save;
399 tree nested, not_nested, nested_ready;
400 tree intr, excp, reset;
401
402 save_all = lookup_attribute ("save_all", func_attrs);
403 partial_save = lookup_attribute ("partial_save", func_attrs);
404
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);
408
409 intr = lookup_attribute ("interrupt", func_attrs);
410 excp = lookup_attribute ("exception", func_attrs);
411 reset = lookup_attribute ("reset", func_attrs);
412
413 /* If there is no interrupt/exception/reset, we can return immediately. */
414 if (!intr && !excp && !reset)
415 return;
416
417 /* If we are here, either we have interrupt/exception,
418 or reset attribute. */
419 if (intr || excp)
420 {
421 tree id_list;
422
423 /* Prepare id list so that we can traverse and set vector id. */
424 id_list = (intr) ? (TREE_VALUE (intr)) : (TREE_VALUE (excp));
425
426 while (id_list)
427 {
428 tree id;
429 int vector_id;
430 unsigned int vector_number_offset;
431
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);
437
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;
442
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);
448
449 /* Set register saving scheme. */
450 if (save_all)
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;
454
455 /* Set nested type. */
456 if (nested)
457 nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED;
458 else if (not_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;
462
463 /* Advance to next id. */
464 id_list = TREE_CHAIN (id_list);
465 }
466 }
467 else
468 {
469 tree id_list;
470 tree id;
471 tree nmi, warm;
472
473 /* Deal with reset attribute. Its vector number is always 0. */
474 nds32_isr_vectors[0].category = NDS32_ISR_RESET;
475
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);
480
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);
485
486 /* Retrieve nmi and warm function. */
487 nmi = lookup_attribute ("nmi", func_attrs);
488 warm = lookup_attribute ("warm", func_attrs);
489
490 if (nmi != NULL_TREE)
491 {
492 tree nmi_func_list;
493 tree nmi_func;
494
495 nmi_func_list = TREE_VALUE (nmi);
496 nmi_func = TREE_VALUE (nmi_func_list);
497
498 /* Record nmi function name. */
499 strcpy (nds32_isr_vectors[0].nmi_name,
500 IDENTIFIER_POINTER (nmi_func));
501 }
502
503 if (warm != NULL_TREE)
504 {
505 tree warm_func_list;
506 tree warm_func;
507
508 warm_func_list = TREE_VALUE (warm);
509 warm_func = TREE_VALUE (warm_func_list);
510
511 /* Record warm function name. */
512 strcpy (nds32_isr_vectors[0].warm_name,
513 IDENTIFIER_POINTER (warm_func));
514 }
515 }
516 }
517
518 /* A helper function to handle isr stuff at the beginning of asm file. */
519 void
520 nds32_asm_file_start_for_isr (void)
521 {
522 int i;
523
524 /* Initialize isr vector information array before compiling functions. */
525 for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
526 {
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, "");
534 }
535 }
536
537 /* A helper function to handle isr stuff at the end of asm file. */
538 void
539 nds32_asm_file_end_for_isr (void)
540 {
541 int i;
542
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)
546 break;
547
548 if (i == NDS32_N_ISR_VECTORS)
549 return;
550
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");
556
557 /* Check reset handler first. Its vector number is always 0. */
558 if (nds32_isr_vectors[0].category == NDS32_ISR_RESET)
559 {
560 nds32_emit_isr_reset_content ();
561 fprintf (asm_out_file, "\t! ------------------------------------\n");
562 }
563
564 /* Check other vectors, starting from vector number 1. */
565 for (i = 1; i < NDS32_N_ISR_VECTORS; i++)
566 {
567 if (nds32_isr_vectors[i].category == NDS32_ISR_INTERRUPT
568 || nds32_isr_vectors[i].category == NDS32_ISR_EXCEPTION)
569 {
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");
578 }
579 }
580 }
581
582 /* Return true if FUNC is a isr function. */
583 bool
584 nds32_isr_function_p (tree func)
585 {
586 tree t_intr;
587 tree t_excp;
588 tree t_reset;
589
590 tree attrs;
591
592 if (TREE_CODE (func) != FUNCTION_DECL)
593 abort ();
594
595 attrs = DECL_ATTRIBUTES (func);
596
597 t_intr = lookup_attribute ("interrupt", attrs);
598 t_excp = lookup_attribute ("exception", attrs);
599 t_reset = lookup_attribute ("reset", attrs);
600
601 return ((t_intr != NULL_TREE)
602 || (t_excp != NULL_TREE)
603 || (t_reset != NULL_TREE));
604 }
605
606 /* ------------------------------------------------------------------------ */