1/* Subroutines used for ISR of Andes NDS32 cpu for GNU compiler 2 Copyright (C) 2012-2020 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#define IN_TARGET_CODE 1 24 25#include "config.h" 26#include "system.h" 27#include "coretypes.h" 28#include "backend.h" 29#include "target.h" 30#include "rtl.h" 31#include "tree.h" 32#include "stringpool.h" 33#include "attribs.h" 34#include "diagnostic-core.h" 35#include "output.h" 36 37/* ------------------------------------------------------------------------ */ 38 39/* Refer to nds32.h, there are maximum 73 isr vectors in nds32 architecture. 40 0 for reset handler with __attribute__((reset())), 41 1-8 for exception handler with __attribute__((exception(1,...,8))), 42 and 9-72 for interrupt handler with __attribute__((interrupt(0,...,63))). 43 We use an array to record essential information for each vector. */ 44static struct nds32_isr_info nds32_isr_vectors[NDS32_N_ISR_VECTORS]; 45 46/* ------------------------------------------------------------- */ 47/* FIXME: 48 FOR BACKWARD COMPATIBILITY, we need to support following patterns: 49 50 __attribute__((interrupt("XXX;YYY;id=ZZZ"))) 51 __attribute__((exception("XXX;YYY;id=ZZZ"))) 52 __attribute__((reset("vectors=XXX;nmi_func=YYY;warm_func=ZZZ"))) 53 54 We provide several functions to parse the strings. */ 55 56static void 57nds32_interrupt_attribute_parse_string (const char *original_str, 58 const char *func_name, 59 unsigned int s_level) 60{ 61 char target_str[100]; 62 enum nds32_isr_save_reg save_reg; 63 enum nds32_isr_nested_type nested_type; 64 65 char *save_all_regs_str, *save_caller_regs_str; 66 char *nested_str, *not_nested_str, *ready_nested_str, *critical_str; 67 char *id_str, *value_str; 68 69 /* Copy original string into a character array so that 70 the string APIs can handle it. */ 71 strcpy (target_str, original_str); 72 73 /* 1. Detect 'save_all_regs' : NDS32_SAVE_ALL 74 'save_caller_regs' : NDS32_PARTIAL_SAVE */ 75 save_all_regs_str = strstr (target_str, "save_all_regs"); 76 save_caller_regs_str = strstr (target_str, "save_caller_regs"); 77 78 /* Note that if no argument is found, 79 use NDS32_PARTIAL_SAVE by default. */ 80 if (save_all_regs_str) 81 save_reg = NDS32_SAVE_ALL; 82 else if (save_caller_regs_str) 83 save_reg = NDS32_PARTIAL_SAVE; 84 else 85 save_reg = NDS32_PARTIAL_SAVE; 86 87 /* 2. Detect 'nested' : NDS32_NESTED 88 'not_nested' : NDS32_NOT_NESTED 89 'ready_nested' : NDS32_NESTED_READY 90 'critical' : NDS32_CRITICAL */ 91 nested_str = strstr (target_str, "nested"); 92 not_nested_str = strstr (target_str, "not_nested"); 93 ready_nested_str = strstr (target_str, "ready_nested"); 94 critical_str = strstr (target_str, "critical"); 95 96 /* Note that if no argument is found, 97 use NDS32_NOT_NESTED by default. 98 Also, since 'not_nested' and 'ready_nested' both contains 99 'nested' string, we check 'nested' with lowest priority. */ 100 if (not_nested_str) 101 nested_type = NDS32_NOT_NESTED; 102 else if (ready_nested_str) 103 nested_type = NDS32_NESTED_READY; 104 else if (nested_str) 105 nested_type = NDS32_NESTED; 106 else if (critical_str) 107 nested_type = NDS32_CRITICAL; 108 else 109 nested_type = NDS32_NOT_NESTED; 110 111 /* 3. Traverse each id value and set corresponding information. */ 112 id_str = strstr (target_str, "id="); 113 114 /* If user forgets to assign 'id', issue an error message. */ 115 if (id_str == NULL) 116 error ("require id argument in the string"); 117 /* Extract the value_str first. */ 118 id_str = strtok (id_str, "="); 119 value_str = strtok (NULL, ";"); 120 121 /* Pick up the first id value token. */ 122 value_str = strtok (value_str, ","); 123 while (value_str != NULL) 124 { 125 int i; 126 i = atoi (value_str); 127 128 /* For interrupt(0..63), the actual vector number is (9..72). */ 129 i = i + 9; 130 if (i < 9 || i > 72) 131 error ("invalid id value for interrupt attribute"); 132 133 /* Setup nds32_isr_vectors[] array. */ 134 nds32_isr_vectors[i].category = NDS32_ISR_INTERRUPT; 135 strcpy (nds32_isr_vectors[i].func_name, func_name); 136 nds32_isr_vectors[i].save_reg = save_reg; 137 nds32_isr_vectors[i].nested_type = nested_type; 138 nds32_isr_vectors[i].security_level = s_level; 139 140 /* Fetch next token. */ 141 value_str = strtok (NULL, ","); 142 } 143 144 return; 145} 146 147static void 148nds32_exception_attribute_parse_string (const char *original_str, 149 const char *func_name, 150 unsigned int s_level) 151{ 152 char target_str[100]; 153 enum nds32_isr_save_reg save_reg; 154 enum nds32_isr_nested_type nested_type; 155 156 char *save_all_regs_str, *save_caller_regs_str; 157 char *nested_str, *not_nested_str, *ready_nested_str, *critical_str; 158 char *id_str, *value_str; 159 160 /* Copy original string into a character array so that 161 the string APIs can handle it. */ 162 strcpy (target_str, original_str); 163 164 /* 1. Detect 'save_all_regs' : NDS32_SAVE_ALL 165 'save_caller_regs' : NDS32_PARTIAL_SAVE */ 166 save_all_regs_str = strstr (target_str, "save_all_regs"); 167 save_caller_regs_str = strstr (target_str, "save_caller_regs"); 168 169 /* Note that if no argument is found, 170 use NDS32_PARTIAL_SAVE by default. */ 171 if (save_all_regs_str) 172 save_reg = NDS32_SAVE_ALL; 173 else if (save_caller_regs_str) 174 save_reg = NDS32_PARTIAL_SAVE; 175 else 176 save_reg = NDS32_PARTIAL_SAVE; 177 178 /* 2. Detect 'nested' : NDS32_NESTED 179 'not_nested' : NDS32_NOT_NESTED 180 'ready_nested' : NDS32_NESTED_READY 181 'critical' : NDS32_CRITICAL */ 182 nested_str = strstr (target_str, "nested"); 183 not_nested_str = strstr (target_str, "not_nested"); 184 ready_nested_str = strstr (target_str, "ready_nested"); 185 critical_str = strstr (target_str, "critical"); 186 187 /* Note that if no argument is found, 188 use NDS32_NOT_NESTED by default. 189 Also, since 'not_nested' and 'ready_nested' both contains 190 'nested' string, we check 'nested' with lowest priority. */ 191 if (not_nested_str) 192 nested_type = NDS32_NOT_NESTED; 193 else if (ready_nested_str) 194 nested_type = NDS32_NESTED_READY; 195 else if (nested_str) 196 nested_type = NDS32_NESTED; 197 else if (critical_str) 198 nested_type = NDS32_CRITICAL; 199 else 200 nested_type = NDS32_NOT_NESTED; 201 202 /* 3. Traverse each id value and set corresponding information. */ 203 id_str = strstr (target_str, "id="); 204 205 /* If user forgets to assign 'id', issue an error message. */ 206 if (id_str == NULL) 207 error ("require id argument in the string"); 208 /* Extract the value_str first. */ 209 id_str = strtok (id_str, "="); 210 value_str = strtok (NULL, ";"); 211 212 /* Pick up the first id value token. */ 213 value_str = strtok (value_str, ","); 214 while (value_str != NULL) 215 { 216 int i; 217 i = atoi (value_str); 218 219 /* For exception(1..8), the actual vector number is (1..8). */ 220 if (i < 1 || i > 8) 221 error ("invalid id value for exception attribute"); 222 223 /* Setup nds32_isr_vectors[] array. */ 224 nds32_isr_vectors[i].category = NDS32_ISR_EXCEPTION; 225 strcpy (nds32_isr_vectors[i].func_name, func_name); 226 nds32_isr_vectors[i].save_reg = save_reg; 227 nds32_isr_vectors[i].nested_type = nested_type; 228 nds32_isr_vectors[i].security_level = s_level; 229 230 /* Fetch next token. */ 231 value_str = strtok (NULL, ","); 232 } 233 234 return; 235} 236 237static void 238nds32_reset_attribute_parse_string (const char *original_str, 239 const char *func_name) 240{ 241 char target_str[100]; 242 char *vectors_str, *nmi_str, *warm_str, *value_str; 243 244 /* Deal with reset attribute. Its vector number is always 0. */ 245 nds32_isr_vectors[0].category = NDS32_ISR_RESET; 246 247 248 /* 1. Parse 'vectors=XXXX'. */ 249 250 /* Copy original string into a character array so that 251 the string APIs can handle it. */ 252 strcpy (target_str, original_str); 253 vectors_str = strstr (target_str, "vectors="); 254 /* The total vectors = interrupt + exception numbers + reset. 255 There are 8 exception and 1 reset in nds32 architecture. 256 If user forgets to assign 'vectors', user default 16 interrupts. */ 257 if (vectors_str != NULL) 258 { 259 /* Extract the value_str. */ 260 vectors_str = strtok (vectors_str, "="); 261 value_str = strtok (NULL, ";"); 262 nds32_isr_vectors[0].total_n_vectors = atoi (value_str) + 8 + 1; 263 } 264 else 265 nds32_isr_vectors[0].total_n_vectors = 16 + 8 + 1; 266 strcpy (nds32_isr_vectors[0].func_name, func_name); 267 268 269 /* 2. Parse 'nmi_func=YYYY'. */ 270 271 /* Copy original string into a character array so that 272 the string APIs can handle it. */ 273 strcpy (target_str, original_str); 274 nmi_str = strstr (target_str, "nmi_func="); 275 if (nmi_str != NULL) 276 { 277 /* Extract the value_str. */ 278 nmi_str = strtok (nmi_str, "="); 279 value_str = strtok (NULL, ";"); 280 strcpy (nds32_isr_vectors[0].nmi_name, value_str); 281 } 282 283 /* 3. Parse 'warm_func=ZZZZ'. */ 284 285 /* Copy original string into a character array so that 286 the string APIs can handle it. */ 287 strcpy (target_str, original_str); 288 warm_str = strstr (target_str, "warm_func="); 289 if (warm_str != NULL) 290 { 291 /* Extract the value_str. */ 292 warm_str = strtok (warm_str, "="); 293 value_str = strtok (NULL, ";"); 294 strcpy (nds32_isr_vectors[0].warm_name, value_str); 295 } 296 297 return; 298} 299/* ------------------------------------------------------------- */ 300 301/* A helper function to emit section head template. */ 302static void 303nds32_emit_section_head_template (char section_name[], 304 char symbol_name[], 305 int align_value, 306 bool object_p) 307{ 308 const char *flags_str; 309 const char *type_str; 310 311 flags_str = (object_p) ? "\"a\"" : "\"ax\""; 312 type_str = (object_p) ? "@object" : "@function"; 313 314 fprintf (asm_out_file, "\t.section\t%s, %s\n", section_name, flags_str); 315 fprintf (asm_out_file, "\t.align\t%d\n", align_value); 316 fprintf (asm_out_file, "\t.global\t%s\n", symbol_name); 317 fprintf (asm_out_file, "\t.type\t%s, %s\n", symbol_name, type_str); 318 fprintf (asm_out_file, "%s:\n", symbol_name); 319} 320 321/* A helper function to emit section tail template. */ 322static void 323nds32_emit_section_tail_template (char symbol_name[]) 324{ 325 fprintf (asm_out_file, "\t.size\t%s, .-%s\n", symbol_name, symbol_name); 326} 327 328/* Function to emit isr jump table section. */ 329static void 330nds32_emit_isr_jmptbl_section (int vector_id) 331{ 332 char section_name[100]; 333 char symbol_name[100]; 334 335 /* A critical isr does not need jump table section because 336 its behavior is not performed by two-level handler. */ 337 if (nds32_isr_vectors[vector_id].nested_type == NDS32_CRITICAL) 338 { 339 fprintf (asm_out_file, "\t! The vector %02d is a critical isr !\n", 340 vector_id); 341 return; 342 } 343 344 /* Prepare jmptbl section and symbol name. */ 345 snprintf (section_name, sizeof (section_name), 346 ".nds32_jmptbl.%02d", vector_id); 347 snprintf (symbol_name, sizeof (symbol_name), 348 "_nds32_jmptbl_%02d", vector_id); 349 350 nds32_emit_section_head_template (section_name, symbol_name, 2, true); 351 fprintf (asm_out_file, "\t.word\t%s\n", 352 nds32_isr_vectors[vector_id].func_name); 353 nds32_emit_section_tail_template (symbol_name); 354} 355 356/* Function to emit isr vector section. */ 357static void 358nds32_emit_isr_vector_section (int vector_id) 359{ 360 unsigned int vector_number_offset = 0; 361 const char *c_str = "CATEGORY"; 362 const char *sr_str = "SR"; 363 const char *nt_str = "NT"; 364 char first_level_handler_name[100]; 365 char section_name[100]; 366 char symbol_name[100]; 367 368 /* Set the vector number offset so that we can calculate 369 the value that user specifies in the attribute. 370 We also prepare the category string for first level handler name. */ 371 switch (nds32_isr_vectors[vector_id].category) 372 { 373 case NDS32_ISR_INTERRUPT: 374 vector_number_offset = 9; 375 c_str = "i"; 376 break; 377 case NDS32_ISR_EXCEPTION: 378 vector_number_offset = 0; 379 c_str = "e"; 380 break; 381 case NDS32_ISR_NONE: 382 case NDS32_ISR_RESET: 383 /* Normally it should not be here. */ 384 gcc_unreachable (); 385 break; 386 } 387 388 /* Prepare save reg string for first level handler name. */ 389 switch (nds32_isr_vectors[vector_id].save_reg) 390 { 391 case NDS32_SAVE_ALL: 392 sr_str = "sa"; 393 break; 394 case NDS32_PARTIAL_SAVE: 395 sr_str = "ps"; 396 break; 397 } 398 399 /* Prepare nested type string for first level handler name. */ 400 switch (nds32_isr_vectors[vector_id].nested_type) 401 { 402 case NDS32_NESTED: 403 nt_str = "ns"; 404 break; 405 case NDS32_NOT_NESTED: 406 nt_str = "nn"; 407 break; 408 case NDS32_NESTED_READY: 409 nt_str = "nr"; 410 break; 411 case NDS32_CRITICAL: 412 /* The critical isr is not performed by two-level handler. */ 413 nt_str = ""; 414 break; 415 } 416 417 /* Now we can create first level handler name. */ 418 if (nds32_isr_vectors[vector_id].security_level == 0) 419 { 420 /* For security level 0, use normal first level handler name. */ 421 snprintf (first_level_handler_name, sizeof (first_level_handler_name), 422 "_nds32_%s_%s_%s", c_str, sr_str, nt_str); 423 } 424 else 425 { 426 /* For security level 1-3, use corresponding spl_1, spl_2, or spl_3. */ 427 snprintf (first_level_handler_name, sizeof (first_level_handler_name), 428 "_nds32_spl_%d", nds32_isr_vectors[vector_id].security_level); 429 } 430 431 /* Prepare vector section and symbol name. */ 432 snprintf (section_name, sizeof (section_name), 433 ".nds32_vector.%02d", vector_id); 434 snprintf (symbol_name, sizeof (symbol_name), 435 "_nds32_vector_%02d", vector_id); 436 437 438 /* Everything is ready. We can start emit vector section content. */ 439 nds32_emit_section_head_template (section_name, symbol_name, 440 floor_log2 (nds32_isr_vector_size), false); 441 442 /* First we check if it is a critical isr. 443 If so, jump to user handler directly; otherwise, the instructions 444 in the vector section may be different according to the vector size. */ 445 if (nds32_isr_vectors[vector_id].nested_type == NDS32_CRITICAL) 446 { 447 /* This block is for critical isr. Jump to user handler directly. */ 448 fprintf (asm_out_file, "\tj\t%s ! jump to user handler directly\n", 449 nds32_isr_vectors[vector_id].func_name); 450 } 451 else if (nds32_isr_vector_size == 4) 452 { 453 /* This block is for 4-byte vector size. 454 Hardware $VID support is necessary and only one instruction 455 is needed in vector section. */ 456 fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n", 457 first_level_handler_name); 458 } 459 else 460 { 461 /* This block is for 16-byte vector size. 462 There is NO hardware $VID so that we need several instructions 463 such as pushing GPRs and preparing software vid at vector section. 464 For pushing GPRs, there are four variations for 465 16-byte vector content and we have to handle each combination. 466 For preparing software vid, note that the vid need to 467 be substracted vector_number_offset. */ 468 if (TARGET_REDUCED_REGS) 469 { 470 if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL) 471 { 472 /* Case of reduced set registers and save_all attribute. */ 473 fprintf (asm_out_file, "\t! reduced set regs + save_all\n"); 474 fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0xf\n"); 475 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r10, 0x0\n"); 476 477 } 478 else 479 { 480 /* Case of reduced set registers and partial_save attribute. */ 481 fprintf (asm_out_file, "\t! reduced set regs + partial_save\n"); 482 fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r15, 0x2\n"); 483 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n"); 484 } 485 } 486 else 487 { 488 if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL) 489 { 490 /* Case of full set registers and save_all attribute. */ 491 fprintf (asm_out_file, "\t! full set regs + save_all\n"); 492 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r27, 0xf\n"); 493 } 494 else 495 { 496 /* Case of full set registers and partial_save attribute. */ 497 fprintf (asm_out_file, "\t! full set regs + partial_save\n"); 498 fprintf (asm_out_file, "\tsmw.adm\t$r15, [$sp], $r27, 0x2\n"); 499 fprintf (asm_out_file, "\tsmw.adm\t$r0, [$sp], $r5, 0x0\n"); 500 } 501 } 502 503 fprintf (asm_out_file, "\tmovi\t$r0, %d ! preparing software vid\n", 504 vector_id - vector_number_offset); 505 fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n", 506 first_level_handler_name); 507 } 508 509 nds32_emit_section_tail_template (symbol_name); 510} 511 512/* Function to emit isr reset handler content. 513 Including all jmptbl/vector references, jmptbl section, 514 vector section, nmi handler section, and warm handler section. */ 515static void 516nds32_emit_isr_reset_content (void) 517{ 518 unsigned int i; 519 unsigned int total_n_vectors; 520 char reset_handler_name[100]; 521 char section_name[100]; 522 char symbol_name[100]; 523 524 total_n_vectors = nds32_isr_vectors[0].total_n_vectors; 525 526 fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - BEGIN !\n"); 527 528 /* Create references in .rodata according to total number of vectors. */ 529 fprintf (asm_out_file, "\t.section\t.rodata\n"); 530 fprintf (asm_out_file, "\t.align\t2\n"); 531 532 /* Emit jmptbl references. */ 533 fprintf (asm_out_file, "\t ! references to jmptbl section entries\n"); 534 for (i = 0; i < total_n_vectors; i++) 535 fprintf (asm_out_file, "\t.word\t_nds32_jmptbl_%02d\n", i); 536 537 /* Emit vector references. */ 538 fprintf (asm_out_file, "\t ! references to vector section entries\n"); 539 for (i = 0; i < total_n_vectors; i++) 540 fprintf (asm_out_file, "\t.word\t_nds32_vector_%02d\n", i); 541 542 /* Emit jmptbl_00 section. */ 543 snprintf (section_name, sizeof (section_name), ".nds32_jmptbl.00"); 544 snprintf (symbol_name, sizeof (symbol_name), "_nds32_jmptbl_00"); 545 546 fprintf (asm_out_file, "\t! ....................................\n"); 547 nds32_emit_section_head_template (section_name, symbol_name, 2, true); 548 fprintf (asm_out_file, "\t.word\t%s\n", 549 nds32_isr_vectors[0].func_name); 550 nds32_emit_section_tail_template (symbol_name); 551 552 /* Emit vector_00 section. */ 553 snprintf (section_name, sizeof (section_name), ".nds32_vector.00"); 554 snprintf (symbol_name, sizeof (symbol_name), "_nds32_vector_00"); 555 snprintf (reset_handler_name, sizeof (reset_handler_name), 556 "_nds32_reset"); 557 558 fprintf (asm_out_file, "\t! ....................................\n"); 559 nds32_emit_section_head_template (section_name, symbol_name, 560 floor_log2 (nds32_isr_vector_size), false); 561 fprintf (asm_out_file, "\tj\t%s ! jump to reset handler\n", 562 reset_handler_name); 563 nds32_emit_section_tail_template (symbol_name); 564 565 /* Emit nmi handler section. */ 566 snprintf (section_name, sizeof (section_name), ".nds32_nmih"); 567 snprintf (symbol_name, sizeof (symbol_name), "_nds32_nmih"); 568 569 fprintf (asm_out_file, "\t! ....................................\n"); 570 nds32_emit_section_head_template (section_name, symbol_name, 2, true); 571 fprintf (asm_out_file, "\t.word\t%s\n", 572 (strlen (nds32_isr_vectors[0].nmi_name) == 0) 573 ? "0" 574 : nds32_isr_vectors[0].nmi_name); 575 nds32_emit_section_tail_template (symbol_name); 576 577 /* Emit warm handler section. */ 578 snprintf (section_name, sizeof (section_name), ".nds32_wrh"); 579 snprintf (symbol_name, sizeof (symbol_name), "_nds32_wrh"); 580 581 fprintf (asm_out_file, "\t! ....................................\n"); 582 nds32_emit_section_head_template (section_name, symbol_name, 2, true); 583 fprintf (asm_out_file, "\t.word\t%s\n", 584 (strlen (nds32_isr_vectors[0].warm_name) == 0) 585 ? "0" 586 : nds32_isr_vectors[0].warm_name); 587 nds32_emit_section_tail_template (symbol_name); 588 589 fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - END !\n"); 590} 591 592/* Function for nds32_merge_decl_attributes() and nds32_insert_attributes() 593 to check if there are any conflict isr-specific attributes being set. 594 We need to check: 595 1. Only 'save_all' or 'partial_save' in the attributes. 596 2. Only 'nested', 'not_nested', or 'nested_ready' in the attributes. 597 3. Only 'interrupt', 'exception', or 'reset' in the attributes. */ 598void 599nds32_check_isr_attrs_conflict (tree func_decl, tree func_attrs) 600{ 601 int save_all_p, partial_save_p; 602 int nested_p, not_nested_p, nested_ready_p, critical_p; 603 int intr_p, excp_p, reset_p; 604 605 /* Initialize variables. */ 606 save_all_p = partial_save_p = 0; 607 nested_p = not_nested_p = nested_ready_p = critical_p = 0; 608 intr_p = excp_p = reset_p = 0; 609 610 /* We must check at MOST one attribute to set save-reg. */ 611 if (lookup_attribute ("save_all", func_attrs)) 612 save_all_p = 1; 613 if (lookup_attribute ("partial_save", func_attrs)) 614 partial_save_p = 1; 615 616 if ((save_all_p + partial_save_p) > 1) 617 error ("multiple save reg attributes to function %qD", func_decl); 618 619 /* We must check at MOST one attribute to set nested-type. */ 620 if (lookup_attribute ("nested", func_attrs)) 621 nested_p = 1; 622 if (lookup_attribute ("not_nested", func_attrs)) 623 not_nested_p = 1; 624 if (lookup_attribute ("nested_ready", func_attrs)) 625 nested_ready_p = 1; 626 if (lookup_attribute ("critical", func_attrs)) 627 critical_p = 1; 628 629 if ((nested_p + not_nested_p + nested_ready_p + critical_p) > 1) 630 error ("multiple nested types attributes to function %qD", func_decl); 631 632 /* We must check at MOST one attribute to 633 set interrupt/exception/reset. */ 634 if (lookup_attribute ("interrupt", func_attrs)) 635 intr_p = 1; 636 if (lookup_attribute ("exception", func_attrs)) 637 excp_p = 1; 638 if (lookup_attribute ("reset", func_attrs)) 639 reset_p = 1; 640 641 if ((intr_p + excp_p + reset_p) > 1) 642 error ("multiple interrupt attributes to function %qD", func_decl); 643 644 /* Do not allow isr attributes under linux toolchain. */ 645 if (TARGET_LINUX_ABI && intr_p) 646 error ("cannot use interrupt attributes to function %qD " 647 "under linux toolchain", func_decl); 648 if (TARGET_LINUX_ABI && excp_p) 649 error ("cannot use exception attributes to function %qD " 650 "under linux toolchain", func_decl); 651 if (TARGET_LINUX_ABI && reset_p) 652 error ("cannot use reset attributes to function %qD " 653 "under linux toolchain", func_decl); 654} 655 656/* Function to construct isr vectors information array. 657 We DO NOT HAVE TO check if the attributes are valid 658 because those works are supposed to be done on 659 nds32_merge_decl_attributes() and nds32_insert_attributes(). */ 660void 661nds32_construct_isr_vectors_information (tree func_attrs, 662 const char *func_name) 663{ 664 tree save_all, partial_save; 665 tree nested, not_nested, nested_ready, critical; 666 tree intr, excp, reset; 667 668 tree secure; 669 tree security_level_list; 670 tree security_level; 671 unsigned int s_level; 672 673 save_all = lookup_attribute ("save_all", func_attrs); 674 partial_save = lookup_attribute ("partial_save", func_attrs); 675 676 nested = lookup_attribute ("nested", func_attrs); 677 not_nested = lookup_attribute ("not_nested", func_attrs); 678 nested_ready = lookup_attribute ("nested_ready", func_attrs); 679 critical = lookup_attribute ("critical", func_attrs); 680 681 intr = lookup_attribute ("interrupt", func_attrs); 682 excp = lookup_attribute ("exception", func_attrs); 683 reset = lookup_attribute ("reset", func_attrs); 684 685 /* If there is no interrupt/exception/reset, we can return immediately. */ 686 if (!intr && !excp && !reset) 687 return; 688 689 /* At first, we need to retrieve security level. */ 690 secure = lookup_attribute ("secure", func_attrs); 691 if (secure != NULL) 692 { 693 security_level_list = TREE_VALUE (secure); 694 security_level = TREE_VALUE (security_level_list); 695 s_level = TREE_INT_CST_LOW (security_level); 696 } 697 else 698 { 699 /* If there is no secure attribute, the security level is set by 700 nds32_isr_secure_level, which is controlled by -misr-secure=X option. 701 By default nds32_isr_secure_level should be 0. */ 702 s_level = nds32_isr_secure_level; 703 } 704 705 /* ------------------------------------------------------------- */ 706 /* FIXME: 707 FOR BACKWARD COMPATIBILITY, we need to support following patterns: 708 709 __attribute__((interrupt("XXX;YYY;id=ZZZ"))) 710 __attribute__((exception("XXX;YYY;id=ZZZ"))) 711 __attribute__((reset("vectors=XXX;nmi_func=YYY;warm_func=ZZZ"))) 712 713 If interrupt/exception/reset appears and its argument is a 714 STRING_CST, we will parse string with some auxiliary functions 715 which set necessary isr information in the nds32_isr_vectors[] array. 716 After that, we can return immediately to avoid new-syntax isr 717 information construction. */ 718 if (intr != NULL_TREE 719 && TREE_CODE (TREE_VALUE (TREE_VALUE (intr))) == STRING_CST) 720 { 721 tree string_arg = TREE_VALUE (TREE_VALUE (intr)); 722 nds32_interrupt_attribute_parse_string (TREE_STRING_POINTER (string_arg), 723 func_name, 724 s_level); 725 return; 726 } 727 if (excp != NULL_TREE 728 && TREE_CODE (TREE_VALUE (TREE_VALUE (excp))) == STRING_CST) 729 { 730 tree string_arg = TREE_VALUE (TREE_VALUE (excp)); 731 nds32_exception_attribute_parse_string (TREE_STRING_POINTER (string_arg), 732 func_name, 733 s_level); 734 return; 735 } 736 if (reset != NULL_TREE 737 && TREE_CODE (TREE_VALUE (TREE_VALUE (reset))) == STRING_CST) 738 { 739 tree string_arg = TREE_VALUE (TREE_VALUE (reset)); 740 nds32_reset_attribute_parse_string (TREE_STRING_POINTER (string_arg), 741 func_name); 742 return; 743 } 744 /* ------------------------------------------------------------- */ 745 746 /* If we are here, either we have interrupt/exception, 747 or reset attribute. */ 748 if (intr || excp) 749 { 750 tree id_list; 751 752 /* Prepare id list so that we can traverse and set vector id. */ 753 id_list = (intr) ? (TREE_VALUE (intr)) : (TREE_VALUE (excp)); 754 755 while (id_list) 756 { 757 tree id; 758 int vector_id; 759 unsigned int vector_number_offset; 760 761 /* The way to handle interrupt or exception is the same, 762 we just need to take care of actual vector number. 763 For interrupt(0..63), the actual vector number is (9..72). 764 For exception(1..8), the actual vector number is (1..8). */ 765 vector_number_offset = (intr) ? (9) : (0); 766 767 /* Pick up each vector id value. */ 768 id = TREE_VALUE (id_list); 769 /* Add vector_number_offset to get actual vector number. */ 770 vector_id = TREE_INT_CST_LOW (id) + vector_number_offset; 771 772 /* Set security level. */ 773 nds32_isr_vectors[vector_id].security_level = s_level; 774 775 /* Enable corresponding vector and set function name. */ 776 nds32_isr_vectors[vector_id].category = (intr) 777 ? (NDS32_ISR_INTERRUPT) 778 : (NDS32_ISR_EXCEPTION); 779 strcpy (nds32_isr_vectors[vector_id].func_name, func_name); 780 781 /* Set register saving scheme. */ 782 if (save_all) 783 nds32_isr_vectors[vector_id].save_reg = NDS32_SAVE_ALL; 784 else if (partial_save) 785 nds32_isr_vectors[vector_id].save_reg = NDS32_PARTIAL_SAVE; 786 787 /* Set nested type. */ 788 if (nested) 789 nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED; 790 else if (not_nested) 791 nds32_isr_vectors[vector_id].nested_type = NDS32_NOT_NESTED; 792 else if (nested_ready) 793 nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED_READY; 794 else if (critical) 795 nds32_isr_vectors[vector_id].nested_type = NDS32_CRITICAL; 796 797 /* Advance to next id. */ 798 id_list = TREE_CHAIN (id_list); 799 } 800 } 801 else 802 { 803 tree id_list; 804 tree id; 805 tree nmi, warm; 806 807 /* Deal with reset attribute. Its vector number is always 0. */ 808 nds32_isr_vectors[0].category = NDS32_ISR_RESET; 809 810 /* Prepare id_list and identify id value so that 811 we can set total number of vectors. */ 812 id_list = TREE_VALUE (reset); 813 id = TREE_VALUE (id_list); 814 815 /* The total vectors = interrupt + exception numbers + reset. 816 There are 8 exception and 1 reset in nds32 architecture. */ 817 nds32_isr_vectors[0].total_n_vectors = TREE_INT_CST_LOW (id) + 8 + 1; 818 strcpy (nds32_isr_vectors[0].func_name, func_name); 819 820 /* Retrieve nmi and warm function. */ 821 nmi = lookup_attribute ("nmi", func_attrs); 822 warm = lookup_attribute ("warm", func_attrs); 823 824 if (nmi != NULL_TREE) 825 { 826 tree nmi_func_list; 827 tree nmi_func; 828 829 nmi_func_list = TREE_VALUE (nmi); 830 nmi_func = TREE_VALUE (nmi_func_list); 831 832 /* Record nmi function name. */ 833 strcpy (nds32_isr_vectors[0].nmi_name, 834 IDENTIFIER_POINTER (nmi_func)); 835 } 836 837 if (warm != NULL_TREE) 838 { 839 tree warm_func_list; 840 tree warm_func; 841 842 warm_func_list = TREE_VALUE (warm); 843 warm_func = TREE_VALUE (warm_func_list); 844 845 /* Record warm function name. */ 846 strcpy (nds32_isr_vectors[0].warm_name, 847 IDENTIFIER_POINTER (warm_func)); 848 } 849 } 850} 851 852void 853nds32_asm_file_start_for_isr (void) 854{ 855 int i; 856 857 /* Initialize isr vector information array before compiling functions. */ 858 for (i = 0; i < NDS32_N_ISR_VECTORS; i++) 859 { 860 nds32_isr_vectors[i].category = NDS32_ISR_NONE; 861 strcpy (nds32_isr_vectors[i].func_name, ""); 862 nds32_isr_vectors[i].save_reg = NDS32_PARTIAL_SAVE; 863 nds32_isr_vectors[i].nested_type = NDS32_NOT_NESTED; 864 nds32_isr_vectors[i].security_level = 0; 865 nds32_isr_vectors[i].total_n_vectors = 0; 866 strcpy (nds32_isr_vectors[i].nmi_name, ""); 867 strcpy (nds32_isr_vectors[i].warm_name, ""); 868 } 869} 870 871void nds32_asm_file_end_for_isr (void) 872{ 873 int i; 874 875 /* If all the vectors are NDS32_ISR_NONE, we can return immediately. */ 876 for (i = 0; i < NDS32_N_ISR_VECTORS; i++) 877 if (nds32_isr_vectors[i].category != NDS32_ISR_NONE) 878 break; 879 880 if (i == NDS32_N_ISR_VECTORS) 881 return; 882 883 /* At least one vector is NOT NDS32_ISR_NONE, 884 we should output isr vector information. */ 885 fprintf (asm_out_file, "\t! ------------------------------------\n"); 886 fprintf (asm_out_file, "\t! The isr vector information:\n"); 887 fprintf (asm_out_file, "\t! ------------------------------------\n"); 888 889 /* Check reset handler first. Its vector number is always 0. */ 890 if (nds32_isr_vectors[0].category == NDS32_ISR_RESET) 891 { 892 nds32_emit_isr_reset_content (); 893 fprintf (asm_out_file, "\t! ------------------------------------\n"); 894 } 895 896 /* Check other vectors, starting from vector number 1. */ 897 for (i = 1; i < NDS32_N_ISR_VECTORS; i++) 898 { 899 if (nds32_isr_vectors[i].category == NDS32_ISR_INTERRUPT 900 || nds32_isr_vectors[i].category == NDS32_ISR_EXCEPTION) 901 { 902 /* Found one vector which is interupt or exception. 903 Output its jmptbl and vector section content. */ 904 fprintf (asm_out_file, "\t! interrupt/exception vector %02d\n", i); 905 fprintf (asm_out_file, "\t! security level: %d\n", 906 nds32_isr_vectors[i].security_level); 907 fprintf (asm_out_file, "\t! ------------------------------------\n"); 908 nds32_emit_isr_jmptbl_section (i); 909 fprintf (asm_out_file, "\t! ....................................\n"); 910 nds32_emit_isr_vector_section (i); 911 fprintf (asm_out_file, "\t! ------------------------------------\n"); 912 } 913 } 914} 915 916/* Return true if FUNC is a isr function. */ 917bool 918nds32_isr_function_p (tree func) 919{ 920 tree t_intr; 921 tree t_excp; 922 tree t_reset; 923 924 tree attrs; 925 926 if (TREE_CODE (func) != FUNCTION_DECL) 927 abort (); 928 929 attrs = DECL_ATTRIBUTES (func); 930 931 t_intr = lookup_attribute ("interrupt", attrs); 932 t_excp = lookup_attribute ("exception", attrs); 933 t_reset = lookup_attribute ("reset", attrs); 934 935 return ((t_intr != NULL_TREE) 936 || (t_excp != NULL_TREE) 937 || (t_reset != NULL_TREE)); 938} 939 940/* Return true if FUNC is a isr function with critical attribute. */ 941bool 942nds32_isr_function_critical_p (tree func) 943{ 944 tree t_intr; 945 tree t_excp; 946 tree t_critical; 947 948 tree attrs; 949 950 if (TREE_CODE (func) != FUNCTION_DECL) 951 abort (); 952 953 attrs = DECL_ATTRIBUTES (func); 954 955 t_intr = lookup_attribute ("interrupt", attrs); 956 t_excp = lookup_attribute ("exception", attrs); 957 958 t_critical = lookup_attribute ("critical", attrs); 959 960 /* If both interrupt and exception attribute does not appear, 961 we can return false immediately. */ 962 if ((t_intr == NULL_TREE) && (t_excp == NULL_TREE)) 963 return false; 964 965 /* Here we can guarantee either interrupt or ecxception attribute 966 does exist, so further check critical attribute. 967 If it also appears, we can return true. */ 968 if (t_critical != NULL_TREE) 969 return true; 970 971 /* ------------------------------------------------------------- */ 972 /* FIXME: 973 FOR BACKWARD COMPATIBILITY, we need to handle string type. 974 If the string 'critical' appears in the interrupt/exception 975 string argument, we can return true. */ 976 if (t_intr != NULL_TREE || t_excp != NULL_TREE) 977 { 978 char target_str[100]; 979 char *critical_str; 980 tree t_check; 981 tree string_arg; 982 983 t_check = t_intr ? t_intr : t_excp; 984 if (TREE_CODE (TREE_VALUE (TREE_VALUE (t_check))) == STRING_CST) 985 { 986 string_arg = TREE_VALUE (TREE_VALUE (t_check)); 987 strcpy (target_str, TREE_STRING_POINTER (string_arg)); 988 critical_str = strstr (target_str, "critical"); 989 990 /* Found 'critical' string, so return true. */ 991 if (critical_str) 992 return true; 993 } 994 } 995 /* ------------------------------------------------------------- */ 996 997 /* Other cases, this isr function is not critical type. */ 998 return false; 999} 1000 1001/* ------------------------------------------------------------- */ 1002