1/* This file is part of the program psim. 2 3 Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 */ 20 21 22#ifndef _INTERRUPTS_C_ 23#define _INTERRUPTS_C_ 24 25#include <signal.h> 26 27#include "cpu.h" 28#include "idecode.h" 29#include "os_emul.h" 30 31 32/* Operating environment support code 33 34 Unlike the VEA, the OEA must fully model the effect an interrupt 35 has on the processors state. 36 37 Each function below return updated values for registers effected by 38 interrupts */ 39 40 41STATIC_INLINE_INTERRUPTS\ 42(msreg) 43interrupt_msr(msreg old_msr, 44 msreg msr_clear, 45 msreg msr_set) 46{ 47 msreg msr_set_to_0 = (msr_branch_trace_enable 48 | msr_data_relocate 49 | msr_external_interrupt_enable 50 | msr_floating_point_exception_mode_0 51 | msr_floating_point_exception_mode_1 52 | msr_floating_point_available 53 | msr_instruction_relocate 54 | msr_power_management_enable 55 | msr_problem_state 56 | msr_recoverable_interrupt 57 | msr_single_step_trace_enable); 58 /* remember, in 32bit mode msr_64bit_mode is zero */ 59 msreg new_msr = ((((old_msr & ~msr_set_to_0) 60 | msr_64bit_mode) 61 & ~msr_clear) 62 | msr_set); 63 return new_msr; 64} 65 66 67STATIC_INLINE_INTERRUPTS\ 68(msreg) 69interrupt_srr1(msreg old_msr, 70 msreg srr1_clear, 71 msreg srr1_set) 72{ 73 spreg srr1_mask = (MASK(0,32) 74 | MASK(37, 41) 75 | MASK(48, 63)); 76 spreg srr1 = (old_msr & srr1_mask & ~srr1_clear) | srr1_set; 77 return srr1; 78} 79 80 81STATIC_INLINE_INTERRUPTS\ 82(unsigned_word) 83interrupt_base_ea(msreg msr) 84{ 85 if (msr & msr_interrupt_prefix) 86 return MASK(0, 43); 87 else 88 return 0; 89} 90 91 92/* finish off an interrupt for the OEA model, updating all registers 93 and forcing a restart of the processor */ 94 95STATIC_INLINE_INTERRUPTS\ 96(unsigned_word) 97perform_oea_interrupt(cpu *processor, 98 unsigned_word cia, 99 unsigned_word vector_offset, 100 msreg msr_clear, 101 msreg msr_set, 102 msreg srr1_clear, 103 msreg srr1_set) 104{ 105 msreg old_msr = MSR; 106 msreg new_msr = interrupt_msr(old_msr, msr_clear, msr_set); 107 unsigned_word nia; 108 if (!(old_msr & msr_recoverable_interrupt)) { 109 cpu_error(processor, cia, 110 "double interrupt - MSR[RI] bit clear when attempting to deliver interrupt, cia=0x%lx, msr=0x%lx; srr0=0x%lx(cia), srr1=0x%lx(msr); trap-vector=0x%lx, trap-msr=0x%lx", 111 (unsigned long)cia, 112 (unsigned long)old_msr, 113 (unsigned long)SRR0, 114 (unsigned long)SRR1, 115 (unsigned long)vector_offset, 116 (unsigned long)new_msr); 117 } 118 SRR0 = (spreg)(cia); 119 SRR1 = interrupt_srr1(old_msr, srr1_clear, srr1_set); 120 MSR = new_msr; 121 nia = interrupt_base_ea(new_msr) + vector_offset; 122 cpu_synchronize_context(processor, cia); 123 return nia; 124} 125 126 127INLINE_INTERRUPTS\ 128(void) 129machine_check_interrupt(cpu *processor, 130 unsigned_word cia) 131{ 132 switch (CURRENT_ENVIRONMENT) { 133 134 case USER_ENVIRONMENT: 135 case VIRTUAL_ENVIRONMENT: 136 cpu_error(processor, cia, "machine-check interrupt"); 137 138 case OPERATING_ENVIRONMENT: 139 TRACE(trace_interrupts, ("machine-check interrupt - cia=0x%lx\n", 140 (unsigned long)cia)); 141 cia = perform_oea_interrupt(processor, cia, 0x00200, 0, 0, 0, 0); 142 cpu_restart(processor, cia); 143 144 default: 145 error("internal error - machine_check_interrupt - bad switch"); 146 147 } 148} 149 150 151INLINE_INTERRUPTS\ 152(void) 153data_storage_interrupt(cpu *processor, 154 unsigned_word cia, 155 unsigned_word ea, 156 storage_interrupt_reasons reason, 157 int is_store) 158{ 159 switch (CURRENT_ENVIRONMENT) { 160 161 case USER_ENVIRONMENT: 162 case VIRTUAL_ENVIRONMENT: 163 error("internal error - data_storage_interrupt - should not be called in VEA mode"); 164 break; 165 166 case OPERATING_ENVIRONMENT: 167 { 168 spreg direction = (is_store ? dsisr_store_operation : 0); 169 switch (reason) { 170 case direct_store_storage_interrupt: 171 DSISR = dsisr_direct_store_error_exception | direction; 172 break; 173 case hash_table_miss_storage_interrupt: 174 DSISR = dsisr_hash_table_or_dbat_miss | direction; 175 break; 176 case protection_violation_storage_interrupt: 177 DSISR = dsisr_protection_violation | direction; 178 break; 179 case earwax_violation_storage_interrupt: 180 DSISR = dsisr_earwax_violation | direction; 181 break; 182 case segment_table_miss_storage_interrupt: 183 DSISR = dsisr_segment_table_miss | direction; 184 break; 185 case earwax_disabled_storage_interrupt: 186 DSISR = dsisr_earwax_disabled | direction; 187 break; 188 default: 189 error("internal error - data_storage_interrupt - reason %d not implemented", reason); 190 break; 191 } 192 DAR = (spreg)ea; 193 TRACE(trace_interrupts, ("data storage interrupt - cia=0x%lx DAR=0x%lx DSISR=0x%lx\n", 194 (unsigned long)cia, 195 (unsigned long)DAR, 196 (unsigned long)DSISR)); 197 cia = perform_oea_interrupt(processor, cia, 0x00300, 0, 0, 0, 0); 198 cpu_restart(processor, cia); 199 } 200 201 default: 202 error("internal error - data_storage_interrupt - bad switch"); 203 204 } 205} 206 207 208INLINE_INTERRUPTS\ 209(void) 210instruction_storage_interrupt(cpu *processor, 211 unsigned_word cia, 212 storage_interrupt_reasons reason) 213{ 214 switch (CURRENT_ENVIRONMENT) { 215 216 case USER_ENVIRONMENT: 217 case VIRTUAL_ENVIRONMENT: 218 error("internal error - instruction_storage_interrupt - should not be called in VEA mode"); 219 220 case OPERATING_ENVIRONMENT: 221 { 222 msreg srr1_set; 223 switch(reason) { 224 case hash_table_miss_storage_interrupt: 225 srr1_set = srr1_hash_table_or_ibat_miss; 226 break; 227 case direct_store_storage_interrupt: 228 srr1_set = srr1_direct_store_error_exception; 229 break; 230 case protection_violation_storage_interrupt: 231 srr1_set = srr1_protection_violation; 232 break; 233 case segment_table_miss_storage_interrupt: 234 srr1_set = srr1_segment_table_miss; 235 break; 236 default: 237 srr1_set = 0; 238 error("internal error - instruction_storage_interrupt - reason %d not implemented"); 239 break; 240 } 241 TRACE(trace_interrupts, ("instruction storage interrupt - cia=0x%lx SRR1|=0x%lx\n", 242 (unsigned long)cia, 243 (unsigned long)srr1_set)); 244 cia = perform_oea_interrupt(processor, cia, 0x00400, 0, 0, 0, srr1_set); 245 cpu_restart(processor, cia); 246 } 247 248 default: 249 error("internal error - instruction_storage_interrupt - bad switch"); 250 251 } 252} 253 254 255 256INLINE_INTERRUPTS\ 257(void) 258alignment_interrupt(cpu *processor, 259 unsigned_word cia, 260 unsigned_word ra) 261{ 262 switch (CURRENT_ENVIRONMENT) { 263 264 case USER_ENVIRONMENT: 265 case VIRTUAL_ENVIRONMENT: 266 cpu_error(processor, cia, "alignment interrupt - ra=0x%lx", ra); 267 268 case OPERATING_ENVIRONMENT: 269 DAR = (spreg)ra; 270 DSISR = 0; /* FIXME */ 271 TRACE(trace_interrupts, ("alignment interrupt - cia=0x%lx DAR=0x%lx DSISR=0x%lx\n", 272 (unsigned long)cia, 273 (unsigned long)DAR, 274 (unsigned long)DSISR)); 275 cia = perform_oea_interrupt(processor, cia, 0x00600, 0, 0, 0, 0); 276 cpu_restart(processor, cia); 277 278 default: 279 error("internal error - alignment_interrupt - bad switch"); 280 281 } 282} 283 284 285 286 287INLINE_INTERRUPTS\ 288(void) 289program_interrupt(cpu *processor, 290 unsigned_word cia, 291 program_interrupt_reasons reason) 292{ 293 switch (CURRENT_ENVIRONMENT) { 294 295 case USER_ENVIRONMENT: 296 case VIRTUAL_ENVIRONMENT: 297 switch (reason) { 298 case floating_point_enabled_program_interrupt: 299 cpu_error(processor, cia, "program interrupt - %s", 300 "floating point enabled"); 301 break; 302 case illegal_instruction_program_interrupt: 303 cpu_error(processor, cia, "program interrupt - %s", 304 "illegal instruction"); 305 break; 306 case privileged_instruction_program_interrupt: 307 cpu_error(processor, cia, "program interrupt - %s", 308 "privileged instruction"); 309 break; 310 case trap_program_interrupt: 311 cpu_error(processor, cia, "program interrupt - %s", 312 "trap"); 313 break; 314 case optional_instruction_program_interrupt: 315 cpu_error(processor, cia, "program interrupt - %s", 316 "illegal instruction (optional instruction not supported)"); 317 break; 318 case mpc860c0_instruction_program_interrupt: 319 cpu_error(processor, cia, "program interrupt - %s", 320 "problematic branch detected, see MPC860 C0 errata"); 321 break; 322 default: 323 error("internal error - program_interrupt - reason %d not implemented", reason); 324 } 325 326 case OPERATING_ENVIRONMENT: 327 { 328 msreg srr1_set; 329 switch (reason) { 330 case floating_point_enabled_program_interrupt: 331 srr1_set = srr1_floating_point_enabled; 332 break; 333 case optional_instruction_program_interrupt: 334 case illegal_instruction_program_interrupt: 335 srr1_set = srr1_illegal_instruction; 336 break; 337 case privileged_instruction_program_interrupt: 338 srr1_set = srr1_priviliged_instruction; 339 break; 340 case trap_program_interrupt: 341 srr1_set = srr1_trap; 342 break; 343 case mpc860c0_instruction_program_interrupt: 344 srr1_set = 0; 345 cpu_error(processor, cia, "program interrupt - %s", 346 "problematic branch detected, see MPC860 C0 errata"); 347 break; 348 default: 349 srr1_set = 0; 350 error("internal error - program_interrupt - reason %d not implemented", reason); 351 break; 352 } 353 TRACE(trace_interrupts, ("program interrupt - cia=0x%lx SRR1|=0x%lx\n", 354 (unsigned long)cia, 355 (unsigned long)srr1_set)); 356 cia = perform_oea_interrupt(processor, cia, 0x00700, 0, 0, 0, srr1_set); 357 cpu_restart(processor, cia); 358 } 359 360 default: 361 error("internal error - program_interrupt - bad switch"); 362 363 } 364} 365 366 367INLINE_INTERRUPTS\ 368(void) 369floating_point_unavailable_interrupt(cpu *processor, 370 unsigned_word cia) 371{ 372 switch (CURRENT_ENVIRONMENT) { 373 374 case USER_ENVIRONMENT: 375 case VIRTUAL_ENVIRONMENT: 376 cpu_error(processor, cia, "floating-point unavailable interrupt"); 377 378 case OPERATING_ENVIRONMENT: 379 TRACE(trace_interrupts, ("floating-point unavailable interrupt - cia=0x%lx\n", 380 (unsigned long)cia)); 381 cia = perform_oea_interrupt(processor, cia, 0x00800, 0, 0, 0, 0); 382 cpu_restart(processor, cia); 383 384 default: 385 error("internal error - floating_point_unavailable_interrupt - bad switch"); 386 387 } 388} 389 390 391INLINE_INTERRUPTS\ 392(void) 393system_call_interrupt(cpu *processor, 394 unsigned_word cia) 395{ 396 TRACE(trace_interrupts, ("system-call interrupt - cia=0x%lx\n", (unsigned long)cia)); 397 398 switch (CURRENT_ENVIRONMENT) { 399 400 case USER_ENVIRONMENT: 401 case VIRTUAL_ENVIRONMENT: 402 os_emul_system_call(processor, cia); 403 cpu_restart(processor, cia+4); 404 405 case OPERATING_ENVIRONMENT: 406 cia = perform_oea_interrupt(processor, cia+4, 0x00c00, 0, 0, 0, 0); 407 cpu_restart(processor, cia); 408 409 default: 410 error("internal error - system_call_interrupt - bad switch"); 411 412 } 413} 414 415INLINE_INTERRUPTS\ 416(void) 417floating_point_assist_interrupt(cpu *processor, 418 unsigned_word cia) 419{ 420 switch (CURRENT_ENVIRONMENT) { 421 422 case USER_ENVIRONMENT: 423 case VIRTUAL_ENVIRONMENT: 424 cpu_error(processor, cia, "floating-point assist interrupt"); 425 426 case OPERATING_ENVIRONMENT: 427 TRACE(trace_interrupts, ("floating-point assist interrupt - cia=0x%lx\n", (unsigned long)cia)); 428 cia = perform_oea_interrupt(processor, cia, 0x00e00, 0, 0, 0, 0); 429 cpu_restart(processor, cia); 430 431 default: 432 error("internal error - floating_point_assist_interrupt - bad switch"); 433 434 } 435} 436 437 438 439/* handle an externally generated event or an interrupt that has just 440 been enabled through changes to the MSR. */ 441 442STATIC_INLINE_INTERRUPTS\ 443(void) 444deliver_hardware_interrupt(void *data) 445{ 446 cpu *processor = (cpu*)data; 447 interrupts *ints = cpu_interrupts(processor); 448 ints->delivery_scheduled = NULL; 449 if ((cpu_registers(processor)->msr & (msr_floating_point_exception_mode_0 450 | msr_floating_point_exception_mode_1)) 451 && cpu_registers(processor)->fpscr & fpscr_fex) { 452 msreg srr1_set = srr1_floating_point_enabled | srr1_subsequent_instruction; 453 unsigned_word cia = cpu_get_program_counter(processor); 454 unsigned_word nia = perform_oea_interrupt(processor, 455 cia, 0x00700, 0, 0, 0, srr1_set); 456 cpu_set_program_counter(processor, nia); 457 } 458 else if (cpu_registers(processor)->msr & msr_external_interrupt_enable) { 459 /* external interrupts have a high priority and remain pending */ 460 if (ints->pending_interrupts & external_interrupt_pending) { 461 unsigned_word cia = cpu_get_program_counter(processor); 462 unsigned_word nia = perform_oea_interrupt(processor, 463 cia, 0x00500, 0, 0, 0, 0); 464 TRACE(trace_interrupts, ("external interrupt - cia=0x%lx\n", (unsigned long)cia)); 465 cpu_set_program_counter(processor, nia); 466 } 467 /* decrementer interrupts have a lower priority and are once only */ 468 else if (ints->pending_interrupts & decrementer_interrupt_pending) { 469 unsigned_word cia = cpu_get_program_counter(processor); 470 unsigned_word nia = perform_oea_interrupt(processor, 471 cia, 0x00900, 0, 0, 0, 0); 472 TRACE(trace_interrupts, ("decrementer interrupt - cia 0x%lx, time %ld\n", 473 (unsigned long)cia, 474 (unsigned long)event_queue_time(psim_event_queue(cpu_system(processor))) 475 )); 476 cpu_set_program_counter(processor, nia); 477 ints->pending_interrupts &= ~decrementer_interrupt_pending; 478 } 479 } 480} 481 482STATIC_INLINE_INTERRUPTS\ 483(void) 484schedule_hardware_interrupt_delivery(cpu *processor) 485{ 486 interrupts *ints = cpu_interrupts(processor); 487 if (ints->delivery_scheduled == NULL) { 488 ints->delivery_scheduled = 489 event_queue_schedule(psim_event_queue(cpu_system(processor)), 490 0, deliver_hardware_interrupt, processor); 491 } 492} 493 494 495INLINE_INTERRUPTS\ 496(void) 497check_masked_interrupts(cpu *processor) 498{ 499 if (((cpu_registers(processor)->msr & (msr_floating_point_exception_mode_0 500 | msr_floating_point_exception_mode_1)) 501 && cpu_registers(processor)->fpscr & fpscr_fex) 502 || ((cpu_registers(processor)->msr & msr_external_interrupt_enable) 503 && (cpu_interrupts(processor)->pending_interrupts))) 504 schedule_hardware_interrupt_delivery(processor); 505} 506 507INLINE_INTERRUPTS\ 508(void) 509decrementer_interrupt(cpu *processor) 510{ 511 interrupts *ints = cpu_interrupts(processor); 512 ints->pending_interrupts |= decrementer_interrupt_pending; 513 if (cpu_registers(processor)->msr & msr_external_interrupt_enable) { 514 schedule_hardware_interrupt_delivery(processor); 515 } 516} 517 518INLINE_INTERRUPTS\ 519(void) 520external_interrupt(cpu *processor, 521 int is_asserted) 522{ 523 interrupts *ints = cpu_interrupts(processor); 524 if (is_asserted) { 525 if (!(ints->pending_interrupts & external_interrupt_pending)) { 526 ints->pending_interrupts |= external_interrupt_pending; 527 if (cpu_registers(processor)->msr & msr_external_interrupt_enable) 528 schedule_hardware_interrupt_delivery(processor); 529 } 530 else { 531 /* check that we haven't missed out on a chance to deliver an 532 interrupt */ 533 ASSERT(!(cpu_registers(processor)->msr & msr_external_interrupt_enable)); 534 } 535 } 536 else { 537 ints->pending_interrupts &= ~external_interrupt_pending; 538 } 539} 540 541#endif /* _INTERRUPTS_C_ */ 542