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