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