1 /* interrupts.c -- 68HC11 Interrupts Emulation 2 Copyright 1999-2017 Free Software Foundation, Inc. 3 Written by Stephane Carrez (stcarrez@nerim.fr) 4 5 This file is part of GDB, GAS, and the GNU binutils. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 #include "sim-main.h" 21 #include "sim-options.h" 22 23 static const char *interrupt_names[] = { 24 "R1", 25 "R2", 26 "R3", 27 "R4", 28 "R5", 29 "R6", 30 "R7", 31 "R8", 32 "R9", 33 "R10", 34 "R11", 35 36 "SCI", 37 "SPI", 38 "AINPUT", 39 "AOVERFLOW", 40 "TOVERFLOW", 41 "OUT5", 42 "OUT4", 43 "OUT3", 44 "OUT2", 45 "OUT1", 46 "INC3", 47 "INC2", 48 "INC1", 49 "RT", 50 "IRQ", 51 "XIRQ", 52 "SWI", 53 "ILL", 54 "COPRESET", 55 "COPFAIL", 56 "RESET" 57 }; 58 59 struct interrupt_def idefs[] = { 60 /* Serial interrupts. */ 61 { M6811_INT_SCI, M6811_SCSR, M6811_TDRE, M6811_SCCR2, M6811_TIE }, 62 { M6811_INT_SCI, M6811_SCSR, M6811_TC, M6811_SCCR2, M6811_TCIE }, 63 { M6811_INT_SCI, M6811_SCSR, M6811_RDRF, M6811_SCCR2, M6811_RIE }, 64 { M6811_INT_SCI, M6811_SCSR, M6811_IDLE, M6811_SCCR2, M6811_ILIE }, 65 66 /* SPI interrupts. */ 67 { M6811_INT_SPI, M6811_SPSR, M6811_SPIF, M6811_SPCR, M6811_SPIE }, 68 69 /* Realtime interrupts. */ 70 { M6811_INT_TCTN, M6811_TFLG2, M6811_TOF, M6811_TMSK2, M6811_TOI }, 71 { M6811_INT_RT, M6811_TFLG2, M6811_RTIF, M6811_TMSK2, M6811_RTII }, 72 73 /* Output compare interrupts. */ 74 { M6811_INT_OUTCMP1, M6811_TFLG1, M6811_OC1F, M6811_TMSK1, M6811_OC1I }, 75 { M6811_INT_OUTCMP2, M6811_TFLG1, M6811_OC2F, M6811_TMSK1, M6811_OC2I }, 76 { M6811_INT_OUTCMP3, M6811_TFLG1, M6811_OC3F, M6811_TMSK1, M6811_OC3I }, 77 { M6811_INT_OUTCMP4, M6811_TFLG1, M6811_OC4F, M6811_TMSK1, M6811_OC4I }, 78 { M6811_INT_OUTCMP5, M6811_TFLG1, M6811_OC5F, M6811_TMSK1, M6811_OC5I }, 79 80 /* Input compare interrupts. */ 81 { M6811_INT_INCMP1, M6811_TFLG1, M6811_IC1F, M6811_TMSK1, M6811_IC1I }, 82 { M6811_INT_INCMP2, M6811_TFLG1, M6811_IC2F, M6811_TMSK1, M6811_IC2I }, 83 { M6811_INT_INCMP3, M6811_TFLG1, M6811_IC3F, M6811_TMSK1, M6811_IC3I }, 84 85 /* Pulse accumulator. */ 86 { M6811_INT_AINPUT, M6811_TFLG2, M6811_PAIF, M6811_TMSK2, M6811_PAII }, 87 { M6811_INT_AOVERFLOW,M6811_TFLG2, M6811_PAOVF, M6811_TMSK2, M6811_PAOVI}, 88 #if 0 89 { M6811_INT_COPRESET, M6811_CONFIG, M6811_NOCOP, 0, 0 }, 90 { M6811_INT_COPFAIL, M6811_CONFIG, M6811_NOCOP, 0, 0 } 91 #endif 92 }; 93 94 #define CYCLES_MAX ((((signed64) 1) << 62) - 1) 95 96 enum 97 { 98 OPTION_INTERRUPT_INFO = OPTION_START, 99 OPTION_INTERRUPT_CATCH, 100 OPTION_INTERRUPT_CLEAR 101 }; 102 103 static DECLARE_OPTION_HANDLER (interrupt_option_handler); 104 105 static const OPTION interrupt_options[] = 106 { 107 { {"interrupt-info", no_argument, NULL, OPTION_INTERRUPT_INFO }, 108 '\0', NULL, "Print information about interrupts", 109 interrupt_option_handler }, 110 { {"interrupt-catch", required_argument, NULL, OPTION_INTERRUPT_CATCH }, 111 '\0', "NAME[,MODE]", 112 "Catch interrupts when they are raised or taken\n" 113 "NAME Name of the interrupt\n" 114 "MODE Optional mode (`taken' or `raised')", 115 interrupt_option_handler }, 116 { {"interrupt-clear", required_argument, NULL, OPTION_INTERRUPT_CLEAR }, 117 '\0', "NAME", "No longer catch the interrupt", 118 interrupt_option_handler }, 119 120 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } 121 }; 122 123 /* Initialize the interrupts module. */ 124 void 125 interrupts_initialize (SIM_DESC sd, sim_cpu *cpu) 126 { 127 struct interrupts *interrupts = &cpu->cpu_interrupts; 128 129 interrupts->cpu = cpu; 130 131 sim_add_option_table (sd, 0, interrupt_options); 132 } 133 134 /* Initialize the interrupts of the processor. */ 135 void 136 interrupts_reset (struct interrupts *interrupts) 137 { 138 int i; 139 140 interrupts->pending_mask = 0; 141 if (interrupts->cpu->cpu_mode & M6811_SMOD) 142 interrupts->vectors_addr = 0xbfc0; 143 else 144 interrupts->vectors_addr = 0xffc0; 145 interrupts->nb_interrupts_raised = 0; 146 interrupts->min_mask_cycles = CYCLES_MAX; 147 interrupts->max_mask_cycles = 0; 148 interrupts->last_mask_cycles = 0; 149 interrupts->start_mask_cycle = -1; 150 interrupts->xirq_start_mask_cycle = -1; 151 interrupts->xirq_max_mask_cycles = 0; 152 interrupts->xirq_min_mask_cycles = CYCLES_MAX; 153 interrupts->xirq_last_mask_cycles = 0; 154 155 for (i = 0; i < M6811_INT_NUMBER; i++) 156 { 157 interrupts->interrupt_order[i] = i; 158 } 159 160 /* Clear the interrupt history table. */ 161 interrupts->history_index = 0; 162 memset (interrupts->interrupts_history, 0, 163 sizeof (interrupts->interrupts_history)); 164 165 memset (interrupts->interrupts, 0, 166 sizeof (interrupts->interrupts)); 167 168 /* In bootstrap mode, initialize the vector table to point 169 to the RAM location. */ 170 if (interrupts->cpu->cpu_mode == M6811_SMOD) 171 { 172 bfd_vma addr = interrupts->vectors_addr; 173 uint16 vector = 0x0100 - 3 * (M6811_INT_NUMBER - 1); 174 for (i = 0; i < M6811_INT_NUMBER; i++) 175 { 176 memory_write16 (interrupts->cpu, addr, vector); 177 addr += 2; 178 vector += 3; 179 } 180 } 181 } 182 183 static int 184 find_interrupt (const char *name) 185 { 186 int i; 187 188 if (name) 189 for (i = 0; i < M6811_INT_NUMBER; i++) 190 if (strcasecmp (name, interrupt_names[i]) == 0) 191 return i; 192 193 return -1; 194 } 195 196 static SIM_RC 197 interrupt_option_handler (SIM_DESC sd, sim_cpu *cpu, 198 int opt, char *arg, int is_command) 199 { 200 char *p; 201 int mode; 202 int id; 203 struct interrupts *interrupts; 204 205 if (cpu == 0) 206 cpu = STATE_CPU (sd, 0); 207 208 interrupts = &cpu->cpu_interrupts; 209 switch (opt) 210 { 211 case OPTION_INTERRUPT_INFO: 212 for (id = 0; id < M6811_INT_NUMBER; id++) 213 { 214 sim_io_eprintf (sd, "%-10.10s ", interrupt_names[id]); 215 switch (interrupts->interrupts[id].stop_mode) 216 { 217 case SIM_STOP_WHEN_RAISED: 218 sim_io_eprintf (sd, "catch raised "); 219 break; 220 221 case SIM_STOP_WHEN_TAKEN: 222 sim_io_eprintf (sd, "catch taken "); 223 break; 224 225 case SIM_STOP_WHEN_RAISED | SIM_STOP_WHEN_TAKEN: 226 sim_io_eprintf (sd, "catch all "); 227 break; 228 229 default: 230 sim_io_eprintf (sd, " "); 231 break; 232 } 233 sim_io_eprintf (sd, "%ld\n", 234 interrupts->interrupts[id].raised_count); 235 } 236 break; 237 238 case OPTION_INTERRUPT_CATCH: 239 p = strchr (arg, ','); 240 if (p) 241 *p++ = 0; 242 243 mode = SIM_STOP_WHEN_RAISED; 244 id = find_interrupt (arg); 245 if (id < 0) 246 sim_io_eprintf (sd, "Interrupt name not recognized: %s\n", arg); 247 248 if (p && strcasecmp (p, "raised") == 0) 249 mode = SIM_STOP_WHEN_RAISED; 250 else if (p && strcasecmp (p, "taken") == 0) 251 mode = SIM_STOP_WHEN_TAKEN; 252 else if (p && strcasecmp (p, "all") == 0) 253 mode = SIM_STOP_WHEN_RAISED | SIM_STOP_WHEN_TAKEN; 254 else if (p) 255 { 256 sim_io_eprintf (sd, "Invalid argument: %s\n", p); 257 break; 258 } 259 if (id >= 0) 260 interrupts->interrupts[id].stop_mode = mode; 261 break; 262 263 case OPTION_INTERRUPT_CLEAR: 264 mode = SIM_STOP_WHEN_RAISED; 265 id = find_interrupt (arg); 266 if (id < 0) 267 sim_io_eprintf (sd, "Interrupt name not recognized: %s\n", arg); 268 else 269 interrupts->interrupts[id].stop_mode = 0; 270 break; 271 } 272 273 return SIM_RC_OK; 274 } 275 276 /* Update the mask of pending interrupts. This operation must be called 277 when the state of some 68HC11 IO register changes. It looks the 278 different registers that indicate a pending interrupt (timer, SCI, SPI, 279 ...) and records the interrupt if it's there and enabled. */ 280 void 281 interrupts_update_pending (struct interrupts *interrupts) 282 { 283 int i; 284 uint8 *ioregs; 285 unsigned long clear_mask; 286 unsigned long set_mask; 287 288 clear_mask = 0; 289 set_mask = 0; 290 ioregs = &interrupts->cpu->ios[0]; 291 292 for (i = 0; i < ARRAY_SIZE (idefs); i++) 293 { 294 struct interrupt_def *idef = &idefs[i]; 295 uint8 data; 296 297 /* Look if the interrupt is enabled. */ 298 if (idef->enable_paddr) 299 { 300 data = ioregs[idef->enable_paddr]; 301 if (!(data & idef->enabled_mask)) 302 { 303 /* Disable it. */ 304 clear_mask |= (1 << idef->int_number); 305 continue; 306 } 307 } 308 309 /* Interrupt is enabled, see if it's there. */ 310 data = ioregs[idef->int_paddr]; 311 if (!(data & idef->int_mask)) 312 { 313 /* Disable it. */ 314 clear_mask |= (1 << idef->int_number); 315 continue; 316 } 317 318 /* Ok, raise it. */ 319 set_mask |= (1 << idef->int_number); 320 } 321 322 /* Some interrupts are shared (M6811_INT_SCI) so clear 323 the interrupts before setting the new ones. */ 324 interrupts->pending_mask &= ~clear_mask; 325 interrupts->pending_mask |= set_mask; 326 327 /* Keep track of when the interrupt is raised by the device. 328 Also implements the breakpoint-on-interrupt. */ 329 if (set_mask) 330 { 331 signed64 cycle = cpu_current_cycle (interrupts->cpu); 332 int must_stop = 0; 333 334 for (i = 0; i < M6811_INT_NUMBER; i++) 335 { 336 if (!(set_mask & (1 << i))) 337 continue; 338 339 interrupts->interrupts[i].cpu_cycle = cycle; 340 if (interrupts->interrupts[i].stop_mode & SIM_STOP_WHEN_RAISED) 341 { 342 must_stop = 1; 343 sim_io_printf (CPU_STATE (interrupts->cpu), 344 "Interrupt %s raised\n", 345 interrupt_names[i]); 346 } 347 } 348 if (must_stop) 349 sim_engine_halt (CPU_STATE (interrupts->cpu), 350 interrupts->cpu, 351 0, cpu_get_pc (interrupts->cpu), 352 sim_stopped, 353 SIM_SIGTRAP); 354 } 355 } 356 357 358 /* Finds the current active and non-masked interrupt. 359 Returns the interrupt number (index in the vector table) or -1 360 if no interrupt can be serviced. */ 361 int 362 interrupts_get_current (struct interrupts *interrupts) 363 { 364 int i; 365 366 if (interrupts->pending_mask == 0) 367 return -1; 368 369 /* SWI and illegal instructions are simulated by an interrupt. 370 They are not maskable. */ 371 if (interrupts->pending_mask & (1 << M6811_INT_SWI)) 372 { 373 interrupts->pending_mask &= ~(1 << M6811_INT_SWI); 374 return M6811_INT_SWI; 375 } 376 if (interrupts->pending_mask & (1 << M6811_INT_ILLEGAL)) 377 { 378 interrupts->pending_mask &= ~(1 << M6811_INT_ILLEGAL); 379 return M6811_INT_ILLEGAL; 380 } 381 382 /* If there is a non maskable interrupt, go for it (unless we are masked 383 by the X-bit. */ 384 if (interrupts->pending_mask & (1 << M6811_INT_XIRQ)) 385 { 386 if (cpu_get_ccr_X (interrupts->cpu) == 0) 387 { 388 interrupts->pending_mask &= ~(1 << M6811_INT_XIRQ); 389 return M6811_INT_XIRQ; 390 } 391 return -1; 392 } 393 394 /* Interrupts are masked, do nothing. */ 395 if (cpu_get_ccr_I (interrupts->cpu) == 1) 396 { 397 return -1; 398 } 399 400 /* Returns the first interrupt number which is pending. 401 The interrupt priority is specified by the table `interrupt_order'. 402 For these interrupts, the pending mask is cleared when the program 403 performs some actions on the corresponding device. If the device 404 is not reset, the interrupt remains and will be re-raised when 405 we return from the interrupt (see 68HC11 pink book). */ 406 for (i = 0; i < M6811_INT_NUMBER; i++) 407 { 408 enum M6811_INT int_number = interrupts->interrupt_order[i]; 409 410 if (interrupts->pending_mask & (1 << int_number)) 411 { 412 return int_number; 413 } 414 } 415 return -1; 416 } 417 418 419 /* Process the current interrupt if there is one. This operation must 420 be called after each instruction to handle the interrupts. If interrupts 421 are masked, it does nothing. */ 422 int 423 interrupts_process (struct interrupts *interrupts) 424 { 425 int id; 426 uint8 ccr; 427 428 /* See if interrupts are enabled/disabled and keep track of the 429 number of cycles the interrupts are masked. Such information is 430 then reported by the info command. */ 431 ccr = cpu_get_ccr (interrupts->cpu); 432 if (ccr & M6811_I_BIT) 433 { 434 if (interrupts->start_mask_cycle < 0) 435 interrupts->start_mask_cycle = cpu_current_cycle (interrupts->cpu); 436 } 437 else if (interrupts->start_mask_cycle >= 0 438 && (ccr & M6811_I_BIT) == 0) 439 { 440 signed64 t = cpu_current_cycle (interrupts->cpu); 441 442 t -= interrupts->start_mask_cycle; 443 if (t < interrupts->min_mask_cycles) 444 interrupts->min_mask_cycles = t; 445 if (t > interrupts->max_mask_cycles) 446 interrupts->max_mask_cycles = t; 447 interrupts->start_mask_cycle = -1; 448 interrupts->last_mask_cycles = t; 449 } 450 if (ccr & M6811_X_BIT) 451 { 452 if (interrupts->xirq_start_mask_cycle < 0) 453 interrupts->xirq_start_mask_cycle 454 = cpu_current_cycle (interrupts->cpu); 455 } 456 else if (interrupts->xirq_start_mask_cycle >= 0 457 && (ccr & M6811_X_BIT) == 0) 458 { 459 signed64 t = cpu_current_cycle (interrupts->cpu); 460 461 t -= interrupts->xirq_start_mask_cycle; 462 if (t < interrupts->xirq_min_mask_cycles) 463 interrupts->xirq_min_mask_cycles = t; 464 if (t > interrupts->xirq_max_mask_cycles) 465 interrupts->xirq_max_mask_cycles = t; 466 interrupts->xirq_start_mask_cycle = -1; 467 interrupts->xirq_last_mask_cycles = t; 468 } 469 470 id = interrupts_get_current (interrupts); 471 if (id >= 0) 472 { 473 uint16 addr; 474 struct interrupt_history *h; 475 476 /* Implement the breakpoint-on-interrupt. */ 477 if (interrupts->interrupts[id].stop_mode & SIM_STOP_WHEN_TAKEN) 478 { 479 sim_io_printf (CPU_STATE (interrupts->cpu), 480 "Interrupt %s will be handled\n", 481 interrupt_names[id]); 482 sim_engine_halt (CPU_STATE (interrupts->cpu), 483 interrupts->cpu, 484 0, cpu_get_pc (interrupts->cpu), 485 sim_stopped, 486 SIM_SIGTRAP); 487 } 488 489 cpu_push_all (interrupts->cpu); 490 addr = memory_read16 (interrupts->cpu, 491 interrupts->vectors_addr + id * 2); 492 cpu_call (interrupts->cpu, addr); 493 494 /* Now, protect from nested interrupts. */ 495 if (id == M6811_INT_XIRQ) 496 { 497 cpu_set_ccr_X (interrupts->cpu, 1); 498 } 499 else 500 { 501 cpu_set_ccr_I (interrupts->cpu, 1); 502 } 503 504 /* Update the interrupt history table. */ 505 h = &interrupts->interrupts_history[interrupts->history_index]; 506 h->type = id; 507 h->taken_cycle = cpu_current_cycle (interrupts->cpu); 508 h->raised_cycle = interrupts->interrupts[id].cpu_cycle; 509 510 if (interrupts->history_index >= MAX_INT_HISTORY-1) 511 interrupts->history_index = 0; 512 else 513 interrupts->history_index++; 514 515 interrupts->nb_interrupts_raised++; 516 cpu_add_cycles (interrupts->cpu, 14); 517 return 1; 518 } 519 return 0; 520 } 521 522 void 523 interrupts_raise (struct interrupts *interrupts, enum M6811_INT number) 524 { 525 interrupts->pending_mask |= (1 << number); 526 interrupts->nb_interrupts_raised ++; 527 } 528 529 void 530 interrupts_info (SIM_DESC sd, struct interrupts *interrupts) 531 { 532 signed64 t, prev_interrupt; 533 int i; 534 535 sim_io_printf (sd, "Interrupts Info:\n"); 536 sim_io_printf (sd, " Interrupts raised: %lu\n", 537 interrupts->nb_interrupts_raised); 538 539 if (interrupts->start_mask_cycle >= 0) 540 { 541 t = cpu_current_cycle (interrupts->cpu); 542 543 t -= interrupts->start_mask_cycle; 544 if (t > interrupts->max_mask_cycles) 545 interrupts->max_mask_cycles = t; 546 547 sim_io_printf (sd, " Current interrupts masked sequence: %s\n", 548 cycle_to_string (interrupts->cpu, t, 549 PRINT_TIME | PRINT_CYCLE)); 550 } 551 t = interrupts->min_mask_cycles == CYCLES_MAX ? 552 interrupts->max_mask_cycles : 553 interrupts->min_mask_cycles; 554 sim_io_printf (sd, " Shortest interrupts masked sequence: %s\n", 555 cycle_to_string (interrupts->cpu, t, 556 PRINT_TIME | PRINT_CYCLE)); 557 558 t = interrupts->max_mask_cycles; 559 sim_io_printf (sd, " Longest interrupts masked sequence: %s\n", 560 cycle_to_string (interrupts->cpu, t, 561 PRINT_TIME | PRINT_CYCLE)); 562 563 t = interrupts->last_mask_cycles; 564 sim_io_printf (sd, " Last interrupts masked sequence: %s\n", 565 cycle_to_string (interrupts->cpu, t, 566 PRINT_TIME | PRINT_CYCLE)); 567 568 if (interrupts->xirq_start_mask_cycle >= 0) 569 { 570 t = cpu_current_cycle (interrupts->cpu); 571 572 t -= interrupts->xirq_start_mask_cycle; 573 if (t > interrupts->xirq_max_mask_cycles) 574 interrupts->xirq_max_mask_cycles = t; 575 576 sim_io_printf (sd, " XIRQ Current interrupts masked sequence: %s\n", 577 cycle_to_string (interrupts->cpu, t, 578 PRINT_TIME | PRINT_CYCLE)); 579 } 580 581 t = interrupts->xirq_min_mask_cycles == CYCLES_MAX ? 582 interrupts->xirq_max_mask_cycles : 583 interrupts->xirq_min_mask_cycles; 584 sim_io_printf (sd, " XIRQ Min interrupts masked sequence: %s\n", 585 cycle_to_string (interrupts->cpu, t, 586 PRINT_TIME | PRINT_CYCLE)); 587 588 t = interrupts->xirq_max_mask_cycles; 589 sim_io_printf (sd, " XIRQ Max interrupts masked sequence: %s\n", 590 cycle_to_string (interrupts->cpu, t, 591 PRINT_TIME | PRINT_CYCLE)); 592 593 t = interrupts->xirq_last_mask_cycles; 594 sim_io_printf (sd, " XIRQ Last interrupts masked sequence: %s\n", 595 cycle_to_string (interrupts->cpu, t, 596 PRINT_TIME | PRINT_CYCLE)); 597 598 if (interrupts->pending_mask) 599 { 600 sim_io_printf (sd, " Pending interrupts : "); 601 for (i = 0; i < M6811_INT_NUMBER; i++) 602 { 603 enum M6811_INT int_number = interrupts->interrupt_order[i]; 604 605 if (interrupts->pending_mask & (1 << int_number)) 606 { 607 sim_io_printf (sd, "%s ", interrupt_names[int_number]); 608 } 609 } 610 sim_io_printf (sd, "\n"); 611 } 612 613 prev_interrupt = 0; 614 sim_io_printf (sd, "N Interrupt Cycle Taken Latency" 615 " Delta between interrupts\n"); 616 for (i = 0; i < MAX_INT_HISTORY; i++) 617 { 618 int which; 619 struct interrupt_history *h; 620 signed64 dt; 621 622 which = interrupts->history_index - i - 1; 623 if (which < 0) 624 which += MAX_INT_HISTORY; 625 h = &interrupts->interrupts_history[which]; 626 if (h->taken_cycle == 0) 627 break; 628 629 dt = h->taken_cycle - h->raised_cycle; 630 sim_io_printf (sd, "%2d %-9.9s %15.15s ", i, 631 interrupt_names[h->type], 632 cycle_to_string (interrupts->cpu, h->taken_cycle, 0)); 633 sim_io_printf (sd, "%15.15s", 634 cycle_to_string (interrupts->cpu, dt, 0)); 635 if (prev_interrupt) 636 { 637 dt = prev_interrupt - h->taken_cycle; 638 sim_io_printf (sd, " %s", 639 cycle_to_string (interrupts->cpu, dt, PRINT_TIME)); 640 } 641 sim_io_printf (sd, "\n"); 642 prev_interrupt = h->taken_cycle; 643 } 644 } 645