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