comparison gcc/config/nds32/nds32-isr.c @ 111:04ced10e8804

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