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