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