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