Mercurial > hg > CbC > CbC_gcc
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 /* ------------------------------------------------------------------------ */ |