Rebase.
[official-gcc.git] / gcc / config / nds32 / nds32-isr.c
blobef0187c39cf9eabb3d9aeea4a24a8c5cdb53bc9b
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.
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 #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"
55 /* ------------------------------------------------------------------------ */
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];
64 /* ------------------------------------------------------------------------ */
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)
73 const char *flags_str;
74 const char *type_str;
76 flags_str = (object_p) ? "\"a\"" : "\"ax\"";
77 type_str = (object_p) ? "@object" : "@function";
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);
86 /* A helper function to emit section tail template. */
87 static void
88 nds32_emit_section_tail_template (char symbol_name[])
90 fprintf (asm_out_file, "\t.size\t%s, .-%s\n", symbol_name, symbol_name);
93 /* Function to emit isr jump table section. */
94 static void
95 nds32_emit_isr_jmptbl_section (int vector_id)
97 char section_name[100];
98 char symbol_name[100];
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);
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);
112 /* Function to emit isr vector section. */
113 static void
114 nds32_emit_isr_vector_section (int vector_id)
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];
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)
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;
145 /* Prepare save reg string for first level handler name. */
146 switch (nds32_isr_vectors[vector_id].save_reg)
148 case NDS32_SAVE_ALL:
149 sr_str = "sa";
150 break;
151 case NDS32_PARTIAL_SAVE:
152 sr_str = "ps";
153 break;
156 /* Prepare nested type string for first level handler name. */
157 switch (nds32_isr_vectors[vector_id].nested_type)
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;
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" : "";
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);
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);
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);
189 /* According to the vector size, the instructions in the
190 vector section may be different. */
191 if (nds32_isr_vector_size == 4)
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);
199 else
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)
210 if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
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");
218 else
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");
226 else
228 if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
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");
234 else
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");
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);
249 nds32_emit_section_tail_template (symbol_name);
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)
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];
265 total_n_vectors = nds32_isr_vectors[0].total_n_vectors;
266 vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
268 fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - BEGIN !\n");
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");
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);
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);
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");
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);
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);
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);
307 /* Emit nmi handler section. */
308 snprintf (section_name, sizeof (section_name), ".nds32_nmih");
309 snprintf (symbol_name, sizeof (symbol_name), "_nds32_nmih");
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);
319 /* Emit warm handler section. */
320 snprintf (section_name, sizeof (section_name), ".nds32_wrh");
321 snprintf (symbol_name, sizeof (symbol_name), "_nds32_wrh");
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);
331 fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - END !\n");
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)
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;
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;
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;
358 if ((save_all_p + partial_save_p) > 1)
359 error ("multiple save reg attributes to function %qD", func_decl);
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;
369 if ((nested_p + not_nested_p + nested_ready_p) > 1)
370 error ("multiple nested types attributes to function %qD", func_decl);
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;
381 if ((intr_p + excp_p + reset_p) > 1)
382 error ("multiple interrupt attributes to function %qD", func_decl);
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)
393 tree save_all, partial_save;
394 tree nested, not_nested, nested_ready;
395 tree intr, excp, reset;
397 save_all = lookup_attribute ("save_all", func_attrs);
398 partial_save = lookup_attribute ("partial_save", func_attrs);
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);
404 intr = lookup_attribute ("interrupt", func_attrs);
405 excp = lookup_attribute ("exception", func_attrs);
406 reset = lookup_attribute ("reset", func_attrs);
408 /* If there is no interrupt/exception/reset, we can return immediately. */
409 if (!intr && !excp && !reset)
410 return;
412 /* If we are here, either we have interrupt/exception,
413 or reset attribute. */
414 if (intr || excp)
416 tree id_list;
418 /* Prepare id list so that we can traverse and set vector id. */
419 id_list = (intr) ? (TREE_VALUE (intr)) : (TREE_VALUE (excp));
421 while (id_list)
423 tree id;
424 int vector_id;
425 unsigned int vector_number_offset;
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);
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;
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);
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;
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;
458 /* Advance to next id. */
459 id_list = TREE_CHAIN (id_list);
462 else
464 tree id_list;
465 tree id;
466 tree nmi, warm;
468 /* Deal with reset attribute. Its vector number is always 0. */
469 nds32_isr_vectors[0].category = NDS32_ISR_RESET;
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);
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);
481 /* Retrieve nmi and warm function. */
482 nmi = lookup_attribute ("nmi", func_attrs);
483 warm = lookup_attribute ("warm", func_attrs);
485 if (nmi != NULL_TREE)
487 tree nmi_func_list;
488 tree nmi_func;
490 nmi_func_list = TREE_VALUE (nmi);
491 nmi_func = TREE_VALUE (nmi_func_list);
493 /* Record nmi function name. */
494 strcpy (nds32_isr_vectors[0].nmi_name,
495 IDENTIFIER_POINTER (nmi_func));
498 if (warm != NULL_TREE)
500 tree warm_func_list;
501 tree warm_func;
503 warm_func_list = TREE_VALUE (warm);
504 warm_func = TREE_VALUE (warm_func_list);
506 /* Record warm function name. */
507 strcpy (nds32_isr_vectors[0].warm_name,
508 IDENTIFIER_POINTER (warm_func));
513 /* A helper function to handle isr stuff at the beginning of asm file. */
514 void
515 nds32_asm_file_start_for_isr (void)
517 int i;
519 /* Initialize isr vector information array before compiling functions. */
520 for (i = 0; i < NDS32_N_ISR_VECTORS; i++)
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, "");
532 /* A helper function to handle isr stuff at the end of asm file. */
533 void
534 nds32_asm_file_end_for_isr (void)
536 int i;
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;
543 if (i == NDS32_N_ISR_VECTORS)
544 return;
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");
552 /* Check reset handler first. Its vector number is always 0. */
553 if (nds32_isr_vectors[0].category == NDS32_ISR_RESET)
555 nds32_emit_isr_reset_content ();
556 fprintf (asm_out_file, "\t! ------------------------------------\n");
559 /* Check other vectors, starting from vector number 1. */
560 for (i = 1; i < NDS32_N_ISR_VECTORS; i++)
562 if (nds32_isr_vectors[i].category == NDS32_ISR_INTERRUPT
563 || nds32_isr_vectors[i].category == NDS32_ISR_EXCEPTION)
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");
577 /* ------------------------------------------------------------------------ */