111
|
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 /* ------------------------------------------------------------------------ */
|