]>
Commit | Line | Data |
---|---|---|
c0c935b5 | 1 | /* Subroutines used for ISR of Andes NDS32 cpu for GNU compiler |
5624e564 | 2 | Copyright (C) 2012-2015 Free Software Foundation, Inc. |
c0c935b5 CJW |
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/>. */ | |
c23a919b CJW |
20 | |
21 | /* ------------------------------------------------------------------------ */ | |
22 | ||
23 | #include "config.h" | |
24 | #include "system.h" | |
25 | #include "coretypes.h" | |
c7131fb2 | 26 | #include "backend.h" |
e11c4407 | 27 | #include "target.h" |
c7131fb2 | 28 | #include "rtl.h" |
e11c4407 | 29 | #include "tree.h" |
c23a919b | 30 | #include "diagnostic-core.h" |
e11c4407 | 31 | #include "output.h" |
c23a919b CJW |
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 | ||
126b11c6 CJW |
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 | ||
c23a919b | 579 | /* ------------------------------------------------------------------------ */ |