]>
Commit | Line | Data |
---|---|---|
c0c935b5 | 1 | /* Subroutines used for ISR of Andes NDS32 cpu for GNU compiler |
cbe34bb5 | 2 | Copyright (C) 2012-2017 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" |
314e6352 ML |
30 | #include "stringpool.h" |
31 | #include "attribs.h" | |
c23a919b | 32 | #include "diagnostic-core.h" |
e11c4407 | 33 | #include "output.h" |
c23a919b CJW |
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 | ||
126b11c6 CJW |
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 | ||
c23a919b | 581 | /* ------------------------------------------------------------------------ */ |