14e98e3e1Schristos /* frv exception and interrupt support 2*854b025fSchristos Copyright (C) 1999-2024 Free Software Foundation, Inc. 34e98e3e1Schristos Contributed by Red Hat. 44e98e3e1Schristos 54e98e3e1Schristos This file is part of the GNU simulators. 64e98e3e1Schristos 74e98e3e1Schristos This program is free software; you can redistribute it and/or modify 84e98e3e1Schristos it under the terms of the GNU General Public License as published by 94e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or 104e98e3e1Schristos (at your option) any later version. 114e98e3e1Schristos 124e98e3e1Schristos This program is distributed in the hope that it will be useful, 134e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 144e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 154e98e3e1Schristos GNU General Public License for more details. 164e98e3e1Schristos 174e98e3e1Schristos You should have received a copy of the GNU General Public License 184e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 194e98e3e1Schristos 204b169a6bSchristos /* This must come before any other includes. */ 214b169a6bSchristos #include "defs.h" 224b169a6bSchristos 234e98e3e1Schristos #define WANT_CPU frvbf 244e98e3e1Schristos #define WANT_CPU_FRVBF 254e98e3e1Schristos 264e98e3e1Schristos #include "sim-main.h" 274b169a6bSchristos #include "sim-signal.h" 284e98e3e1Schristos #include "bfd.h" 294b169a6bSchristos #include <stdlib.h> 304b169a6bSchristos #include "cgen-mem.h" 314e98e3e1Schristos 324e98e3e1Schristos /* FR-V Interrupt table. 334e98e3e1Schristos Describes the interrupts supported by the FR-V. 344e98e3e1Schristos This table *must* be maintained in order of interrupt priority as defined by 354e98e3e1Schristos frv_interrupt_kind. */ 364e98e3e1Schristos #define DEFERRED 1 374e98e3e1Schristos #define PRECISE 1 384e98e3e1Schristos #define ITABLE_ENTRY(name, class, deferral, precision, offset) \ 394e98e3e1Schristos {FRV_##name, FRV_EC_##name, class, deferral, precision, offset} 404e98e3e1Schristos 414e98e3e1Schristos struct frv_interrupt frv_interrupt_table[NUM_FRV_INTERRUPT_KINDS] = 424e98e3e1Schristos { 434e98e3e1Schristos /* External interrupts */ 444e98e3e1Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_1, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x21), 454e98e3e1Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_2, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x22), 464e98e3e1Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_3, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x23), 474e98e3e1Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_4, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x24), 484e98e3e1Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_5, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x25), 494e98e3e1Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_6, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x26), 504e98e3e1Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_7, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x27), 514e98e3e1Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_8, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x28), 524e98e3e1Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_9, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x29), 534e98e3e1Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_10, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2a), 544e98e3e1Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_11, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2b), 554e98e3e1Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_12, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2c), 564e98e3e1Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_13, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2d), 574e98e3e1Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_14, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2e), 584e98e3e1Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_15, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2f), 594e98e3e1Schristos /* Software interrupt */ 604e98e3e1Schristos ITABLE_ENTRY(TRAP_INSTRUCTION, FRV_SOFTWARE_INTERRUPT, !DEFERRED, !PRECISE, 0x80), 614e98e3e1Schristos /* Program interrupts */ 624e98e3e1Schristos ITABLE_ENTRY(COMMIT_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x19), 634e98e3e1Schristos ITABLE_ENTRY(DIVISION_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x17), 644e98e3e1Schristos ITABLE_ENTRY(DATA_STORE_ERROR, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x14), 654e98e3e1Schristos ITABLE_ENTRY(DATA_ACCESS_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x13), 664e98e3e1Schristos ITABLE_ENTRY(DATA_ACCESS_MMU_MISS, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x12), 674e98e3e1Schristos ITABLE_ENTRY(DATA_ACCESS_ERROR, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x11), 684e98e3e1Schristos ITABLE_ENTRY(MP_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x0e), 694e98e3e1Schristos ITABLE_ENTRY(FP_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x0d), 704e98e3e1Schristos ITABLE_ENTRY(MEM_ADDRESS_NOT_ALIGNED, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x10), 714e98e3e1Schristos ITABLE_ENTRY(REGISTER_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x08), 724e98e3e1Schristos ITABLE_ENTRY(MP_DISABLED, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x0b), 734e98e3e1Schristos ITABLE_ENTRY(FP_DISABLED, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x0a), 744e98e3e1Schristos ITABLE_ENTRY(PRIVILEGED_INSTRUCTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x06), 754e98e3e1Schristos ITABLE_ENTRY(ILLEGAL_INSTRUCTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x07), 764e98e3e1Schristos ITABLE_ENTRY(INSTRUCTION_ACCESS_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x03), 774e98e3e1Schristos ITABLE_ENTRY(INSTRUCTION_ACCESS_ERROR, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x02), 784e98e3e1Schristos ITABLE_ENTRY(INSTRUCTION_ACCESS_MMU_MISS, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x01), 794e98e3e1Schristos ITABLE_ENTRY(COMPOUND_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x20), 804e98e3e1Schristos /* Break interrupt */ 814e98e3e1Schristos ITABLE_ENTRY(BREAK_EXCEPTION, FRV_BREAK_INTERRUPT, !DEFERRED, !PRECISE, 0xff), 824e98e3e1Schristos /* Reset interrupt */ 834e98e3e1Schristos ITABLE_ENTRY(RESET, FRV_RESET_INTERRUPT, !DEFERRED, !PRECISE, 0x00) 844e98e3e1Schristos }; 854e98e3e1Schristos 864e98e3e1Schristos /* The current interrupt state. */ 874e98e3e1Schristos struct frv_interrupt_state frv_interrupt_state; 884e98e3e1Schristos 894e98e3e1Schristos /* maintain the address of the start of the previous VLIW insn sequence. */ 904e98e3e1Schristos IADDR previous_vliw_pc; 914e98e3e1Schristos 924e98e3e1Schristos /* Add a break interrupt to the interrupt queue. */ 934e98e3e1Schristos struct frv_interrupt_queue_element * 944e98e3e1Schristos frv_queue_break_interrupt (SIM_CPU *current_cpu) 954e98e3e1Schristos { 964e98e3e1Schristos return frv_queue_interrupt (current_cpu, FRV_BREAK_EXCEPTION); 974e98e3e1Schristos } 984e98e3e1Schristos 994e98e3e1Schristos /* Add a software interrupt to the interrupt queue. */ 1004e98e3e1Schristos struct frv_interrupt_queue_element * 1014e98e3e1Schristos frv_queue_software_interrupt (SIM_CPU *current_cpu, SI offset) 1024e98e3e1Schristos { 1034e98e3e1Schristos struct frv_interrupt_queue_element *new_element 1044e98e3e1Schristos = frv_queue_interrupt (current_cpu, FRV_TRAP_INSTRUCTION); 1054e98e3e1Schristos 1064e98e3e1Schristos struct frv_interrupt *interrupt = & frv_interrupt_table[new_element->kind]; 1074e98e3e1Schristos interrupt->handler_offset = offset; 1084e98e3e1Schristos 1094e98e3e1Schristos return new_element; 1104e98e3e1Schristos } 1114e98e3e1Schristos 1124e98e3e1Schristos /* Add a program interrupt to the interrupt queue. */ 1134e98e3e1Schristos struct frv_interrupt_queue_element * 1144e98e3e1Schristos frv_queue_program_interrupt ( 1154e98e3e1Schristos SIM_CPU *current_cpu, enum frv_interrupt_kind kind 1164e98e3e1Schristos ) 1174e98e3e1Schristos { 1184e98e3e1Schristos return frv_queue_interrupt (current_cpu, kind); 1194e98e3e1Schristos } 1204e98e3e1Schristos 1214e98e3e1Schristos /* Add an external interrupt to the interrupt queue. */ 1224e98e3e1Schristos struct frv_interrupt_queue_element * 1234e98e3e1Schristos frv_queue_external_interrupt ( 1244e98e3e1Schristos SIM_CPU *current_cpu, enum frv_interrupt_kind kind 1254e98e3e1Schristos ) 1264e98e3e1Schristos { 1274e98e3e1Schristos if (! GET_H_PSR_ET () 1284e98e3e1Schristos || (kind != FRV_INTERRUPT_LEVEL_15 && kind < GET_H_PSR_PIL ())) 1294e98e3e1Schristos return NULL; /* Leave it for later. */ 1304e98e3e1Schristos 1314e98e3e1Schristos return frv_queue_interrupt (current_cpu, kind); 1324e98e3e1Schristos } 1334e98e3e1Schristos 1344e98e3e1Schristos /* Add any interrupt to the interrupt queue. It will be added in reverse 1354e98e3e1Schristos priority order. This makes it easy to find the highest priority interrupt 1364e98e3e1Schristos at the end of the queue and to remove it after processing. */ 1374e98e3e1Schristos struct frv_interrupt_queue_element * 1384e98e3e1Schristos frv_queue_interrupt (SIM_CPU *current_cpu, enum frv_interrupt_kind kind) 1394e98e3e1Schristos { 1404e98e3e1Schristos int i; 1414e98e3e1Schristos int j; 1424e98e3e1Schristos int limit = frv_interrupt_state.queue_index; 1434e98e3e1Schristos struct frv_interrupt_queue_element *new_element; 1444e98e3e1Schristos enum frv_interrupt_class iclass; 1454e98e3e1Schristos 1464e98e3e1Schristos if (limit >= FRV_INTERRUPT_QUEUE_SIZE) 1474e98e3e1Schristos abort (); /* TODO: Make the queue dynamic */ 1484e98e3e1Schristos 1494e98e3e1Schristos /* Find the right place in the queue. */ 1504e98e3e1Schristos for (i = 0; i < limit; ++i) 1514e98e3e1Schristos { 1524e98e3e1Schristos if (frv_interrupt_state.queue[i].kind >= kind) 1534e98e3e1Schristos break; 1544e98e3e1Schristos } 1554e98e3e1Schristos 1564e98e3e1Schristos /* Don't queue two external interrupts of the same priority. */ 1574e98e3e1Schristos iclass = frv_interrupt_table[kind].iclass; 1584e98e3e1Schristos if (i < limit && iclass == FRV_EXTERNAL_INTERRUPT) 1594e98e3e1Schristos { 1604e98e3e1Schristos if (frv_interrupt_state.queue[i].kind == kind) 1614e98e3e1Schristos return & frv_interrupt_state.queue[i]; 1624e98e3e1Schristos } 1634e98e3e1Schristos 1644e98e3e1Schristos /* Make room for the new interrupt in this spot. */ 1654e98e3e1Schristos for (j = limit - 1; j >= i; --j) 1664e98e3e1Schristos frv_interrupt_state.queue[j + 1] = frv_interrupt_state.queue[j]; 1674e98e3e1Schristos 1684e98e3e1Schristos /* Add the new interrupt. */ 1694e98e3e1Schristos frv_interrupt_state.queue_index++; 1704e98e3e1Schristos new_element = & frv_interrupt_state.queue[i]; 1714e98e3e1Schristos new_element->kind = kind; 1724e98e3e1Schristos new_element->vpc = CPU_PC_GET (current_cpu); 1734e98e3e1Schristos new_element->u.data_written.length = 0; 1744e98e3e1Schristos frv_set_interrupt_queue_slot (current_cpu, new_element); 1754e98e3e1Schristos 1764e98e3e1Schristos return new_element; 1774e98e3e1Schristos } 1784e98e3e1Schristos 1794e98e3e1Schristos struct frv_interrupt_queue_element * 1804e98e3e1Schristos frv_queue_register_exception_interrupt (SIM_CPU *current_cpu, enum frv_rec rec) 1814e98e3e1Schristos { 1824e98e3e1Schristos struct frv_interrupt_queue_element *new_element = 1834e98e3e1Schristos frv_queue_program_interrupt (current_cpu, FRV_REGISTER_EXCEPTION); 1844e98e3e1Schristos 1854e98e3e1Schristos new_element->u.rec = rec; 1864e98e3e1Schristos 1874e98e3e1Schristos return new_element; 1884e98e3e1Schristos } 1894e98e3e1Schristos 1904e98e3e1Schristos struct frv_interrupt_queue_element * 1914e98e3e1Schristos frv_queue_mem_address_not_aligned_interrupt (SIM_CPU *current_cpu, USI addr) 1924e98e3e1Schristos { 1934e98e3e1Schristos struct frv_interrupt_queue_element *new_element; 1944e98e3e1Schristos USI isr = GET_ISR (); 1954e98e3e1Schristos 1964e98e3e1Schristos /* Make sure that this exception is not masked. */ 1974e98e3e1Schristos if (GET_ISR_EMAM (isr)) 1984e98e3e1Schristos return NULL; 1994e98e3e1Schristos 2004e98e3e1Schristos /* Queue the interrupt. */ 2014e98e3e1Schristos new_element = frv_queue_program_interrupt (current_cpu, 2024e98e3e1Schristos FRV_MEM_ADDRESS_NOT_ALIGNED); 2034e98e3e1Schristos new_element->eaddress = addr; 2044e98e3e1Schristos new_element->u.data_written = frv_interrupt_state.data_written; 2054e98e3e1Schristos frv_interrupt_state.data_written.length = 0; 2064e98e3e1Schristos 2074e98e3e1Schristos return new_element; 2084e98e3e1Schristos } 2094e98e3e1Schristos 2104e98e3e1Schristos struct frv_interrupt_queue_element * 2114e98e3e1Schristos frv_queue_data_access_error_interrupt (SIM_CPU *current_cpu, USI addr) 2124e98e3e1Schristos { 2134e98e3e1Schristos struct frv_interrupt_queue_element *new_element; 2144e98e3e1Schristos new_element = frv_queue_program_interrupt (current_cpu, 2154e98e3e1Schristos FRV_DATA_ACCESS_ERROR); 2164e98e3e1Schristos new_element->eaddress = addr; 2174e98e3e1Schristos return new_element; 2184e98e3e1Schristos } 2194e98e3e1Schristos 2204e98e3e1Schristos struct frv_interrupt_queue_element * 2214e98e3e1Schristos frv_queue_data_access_exception_interrupt (SIM_CPU *current_cpu) 2224e98e3e1Schristos { 2234e98e3e1Schristos return frv_queue_program_interrupt (current_cpu, FRV_DATA_ACCESS_EXCEPTION); 2244e98e3e1Schristos } 2254e98e3e1Schristos 2264e98e3e1Schristos struct frv_interrupt_queue_element * 2274e98e3e1Schristos frv_queue_instruction_access_error_interrupt (SIM_CPU *current_cpu) 2284e98e3e1Schristos { 2294e98e3e1Schristos return frv_queue_program_interrupt (current_cpu, FRV_INSTRUCTION_ACCESS_ERROR); 2304e98e3e1Schristos } 2314e98e3e1Schristos 2324e98e3e1Schristos struct frv_interrupt_queue_element * 2334e98e3e1Schristos frv_queue_instruction_access_exception_interrupt (SIM_CPU *current_cpu) 2344e98e3e1Schristos { 2354e98e3e1Schristos return frv_queue_program_interrupt (current_cpu, FRV_INSTRUCTION_ACCESS_EXCEPTION); 2364e98e3e1Schristos } 2374e98e3e1Schristos 2384e98e3e1Schristos struct frv_interrupt_queue_element * 2394e98e3e1Schristos frv_queue_illegal_instruction_interrupt ( 2404e98e3e1Schristos SIM_CPU *current_cpu, const CGEN_INSN *insn 2414e98e3e1Schristos ) 2424e98e3e1Schristos { 2434e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 2444e98e3e1Schristos switch (STATE_ARCHITECTURE (sd)->mach) 2454e98e3e1Schristos { 2464e98e3e1Schristos case bfd_mach_fr400: 2474e98e3e1Schristos case bfd_mach_fr450: 2484e98e3e1Schristos case bfd_mach_fr550: 2494e98e3e1Schristos break; 2504e98e3e1Schristos default: 2514e98e3e1Schristos /* Some machines generate fp_exception for this case. */ 2524e98e3e1Schristos if (frv_is_float_insn (insn) || frv_is_media_insn (insn)) 2534e98e3e1Schristos { 2544e98e3e1Schristos struct frv_fp_exception_info fp_info = { 2554e98e3e1Schristos FSR_NO_EXCEPTION, FTT_SEQUENCE_ERROR 2564e98e3e1Schristos }; 2574e98e3e1Schristos return frv_queue_fp_exception_interrupt (current_cpu, & fp_info); 2584e98e3e1Schristos } 2594e98e3e1Schristos break; 2604e98e3e1Schristos } 2614e98e3e1Schristos 2624e98e3e1Schristos return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); 2634e98e3e1Schristos } 2644e98e3e1Schristos 2654e98e3e1Schristos struct frv_interrupt_queue_element * 2664e98e3e1Schristos frv_queue_privileged_instruction_interrupt (SIM_CPU *current_cpu, const CGEN_INSN *insn) 2674e98e3e1Schristos { 2684e98e3e1Schristos /* The fr550 has no privileged instruction interrupt. It uses 2694e98e3e1Schristos illegal_instruction. */ 2704e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 2714e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 2724e98e3e1Schristos return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); 2734e98e3e1Schristos 2744e98e3e1Schristos return frv_queue_program_interrupt (current_cpu, FRV_PRIVILEGED_INSTRUCTION); 2754e98e3e1Schristos } 2764e98e3e1Schristos 2774e98e3e1Schristos struct frv_interrupt_queue_element * 2784e98e3e1Schristos frv_queue_float_disabled_interrupt (SIM_CPU *current_cpu) 2794e98e3e1Schristos { 2804e98e3e1Schristos /* The fr550 has no fp_disabled interrupt. It uses illegal_instruction. */ 2814e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 2824e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 2834e98e3e1Schristos return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); 2844e98e3e1Schristos 2854e98e3e1Schristos return frv_queue_program_interrupt (current_cpu, FRV_FP_DISABLED); 2864e98e3e1Schristos } 2874e98e3e1Schristos 2884e98e3e1Schristos struct frv_interrupt_queue_element * 2894e98e3e1Schristos frv_queue_media_disabled_interrupt (SIM_CPU *current_cpu) 2904e98e3e1Schristos { 2914e98e3e1Schristos /* The fr550 has no mp_disabled interrupt. It uses illegal_instruction. */ 2924e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 2934e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 2944e98e3e1Schristos return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); 2954e98e3e1Schristos 2964e98e3e1Schristos return frv_queue_program_interrupt (current_cpu, FRV_MP_DISABLED); 2974e98e3e1Schristos } 2984e98e3e1Schristos 2994e98e3e1Schristos struct frv_interrupt_queue_element * 3004e98e3e1Schristos frv_queue_non_implemented_instruction_interrupt ( 3014e98e3e1Schristos SIM_CPU *current_cpu, const CGEN_INSN *insn 3024e98e3e1Schristos ) 3034e98e3e1Schristos { 3044e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 3054e98e3e1Schristos switch (STATE_ARCHITECTURE (sd)->mach) 3064e98e3e1Schristos { 3074e98e3e1Schristos case bfd_mach_fr400: 3084e98e3e1Schristos case bfd_mach_fr450: 3094e98e3e1Schristos case bfd_mach_fr550: 3104e98e3e1Schristos break; 3114e98e3e1Schristos default: 3124e98e3e1Schristos /* Some machines generate fp_exception or mp_exception for this case. */ 3134e98e3e1Schristos if (frv_is_float_insn (insn)) 3144e98e3e1Schristos { 3154e98e3e1Schristos struct frv_fp_exception_info fp_info = { 3164e98e3e1Schristos FSR_NO_EXCEPTION, FTT_UNIMPLEMENTED_FPOP 3174e98e3e1Schristos }; 3184e98e3e1Schristos return frv_queue_fp_exception_interrupt (current_cpu, & fp_info); 3194e98e3e1Schristos } 3204e98e3e1Schristos if (frv_is_media_insn (insn)) 3214e98e3e1Schristos { 3224e98e3e1Schristos frv_set_mp_exception_registers (current_cpu, MTT_UNIMPLEMENTED_MPOP, 3234e98e3e1Schristos 0); 3244e98e3e1Schristos return NULL; /* no interrupt queued at this time. */ 3254e98e3e1Schristos } 3264e98e3e1Schristos break; 3274e98e3e1Schristos } 3284e98e3e1Schristos 3294e98e3e1Schristos return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); 3304e98e3e1Schristos } 3314e98e3e1Schristos 3324e98e3e1Schristos /* Queue the given fp_exception interrupt. Also update fp_info by removing 3334e98e3e1Schristos masked interrupts and updating the 'slot' flield. */ 3344e98e3e1Schristos struct frv_interrupt_queue_element * 3354e98e3e1Schristos frv_queue_fp_exception_interrupt ( 3364e98e3e1Schristos SIM_CPU *current_cpu, struct frv_fp_exception_info *fp_info 3374e98e3e1Schristos ) 3384e98e3e1Schristos { 3394e98e3e1Schristos SI fsr0 = GET_FSR (0); 3404e98e3e1Schristos int tem = GET_FSR_TEM (fsr0); 3414e98e3e1Schristos int aexc = GET_FSR_AEXC (fsr0); 3424e98e3e1Schristos struct frv_interrupt_queue_element *new_element = NULL; 3434e98e3e1Schristos 3444e98e3e1Schristos /* Update AEXC with the interrupts that are masked. */ 3454e98e3e1Schristos aexc |= fp_info->fsr_mask & ~tem; 3464e98e3e1Schristos SET_FSR_AEXC (fsr0, aexc); 3474e98e3e1Schristos SET_FSR (0, fsr0); 3484e98e3e1Schristos 3494e98e3e1Schristos /* update fsr_mask with the exceptions that are enabled. */ 3504e98e3e1Schristos fp_info->fsr_mask &= tem; 3514e98e3e1Schristos 3524e98e3e1Schristos /* If there is an unmasked interrupt then queue it, unless 3534e98e3e1Schristos this was a non-excepting insn, in which case simply set the NE 3544e98e3e1Schristos status registers. */ 3554e98e3e1Schristos if (frv_interrupt_state.ne_index != NE_NOFLAG 3564e98e3e1Schristos && fp_info->fsr_mask != FSR_NO_EXCEPTION) 3574e98e3e1Schristos { 3584e98e3e1Schristos SET_NE_FLAG (frv_interrupt_state.f_ne_flags, 3594e98e3e1Schristos frv_interrupt_state.ne_index); 3604e98e3e1Schristos /* TODO -- Set NESR for chips which support it. */ 3614e98e3e1Schristos new_element = NULL; 3624e98e3e1Schristos } 3634e98e3e1Schristos else if (fp_info->fsr_mask != FSR_NO_EXCEPTION 3644e98e3e1Schristos || fp_info->ftt == FTT_UNIMPLEMENTED_FPOP 3654e98e3e1Schristos || fp_info->ftt == FTT_SEQUENCE_ERROR 3664e98e3e1Schristos || fp_info->ftt == FTT_INVALID_FR) 3674e98e3e1Schristos { 3684e98e3e1Schristos new_element = frv_queue_program_interrupt (current_cpu, FRV_FP_EXCEPTION); 3694e98e3e1Schristos new_element->u.fp_info = *fp_info; 3704e98e3e1Schristos } 3714e98e3e1Schristos 3724e98e3e1Schristos return new_element; 3734e98e3e1Schristos } 3744e98e3e1Schristos 3754e98e3e1Schristos struct frv_interrupt_queue_element * 3764e98e3e1Schristos frv_queue_division_exception_interrupt (SIM_CPU *current_cpu, enum frv_dtt dtt) 3774e98e3e1Schristos { 3784e98e3e1Schristos struct frv_interrupt_queue_element *new_element = 3794e98e3e1Schristos frv_queue_program_interrupt (current_cpu, FRV_DIVISION_EXCEPTION); 3804e98e3e1Schristos 3814e98e3e1Schristos new_element->u.dtt = dtt; 3824e98e3e1Schristos 3834e98e3e1Schristos return new_element; 3844e98e3e1Schristos } 3854e98e3e1Schristos 3864e98e3e1Schristos /* Check for interrupts caused by illegal insn access. These conditions are 3874e98e3e1Schristos checked in the order specified by the fr400 and fr500 LSI specs. */ 3884e98e3e1Schristos void 3894e98e3e1Schristos frv_detect_insn_access_interrupts (SIM_CPU *current_cpu, SCACHE *sc) 3904e98e3e1Schristos { 3914e98e3e1Schristos 3924e98e3e1Schristos const CGEN_INSN *insn = sc->argbuf.idesc->idata; 3934e98e3e1Schristos FRV_VLIW *vliw = CPU_VLIW (current_cpu); 3944e98e3e1Schristos 3954e98e3e1Schristos /* Check for vliw constraints. */ 3964e98e3e1Schristos if (vliw->constraint_violation) 3974e98e3e1Schristos frv_queue_illegal_instruction_interrupt (current_cpu, insn); 3984e98e3e1Schristos /* Check for non-excepting insns. */ 3994e98e3e1Schristos else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_NON_EXCEPTING) 4004e98e3e1Schristos && ! GET_H_PSR_NEM ()) 4014e98e3e1Schristos frv_queue_non_implemented_instruction_interrupt (current_cpu, insn); 4024e98e3e1Schristos /* Check for conditional insns. */ 4034e98e3e1Schristos else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONDITIONAL) 4044e98e3e1Schristos && ! GET_H_PSR_CM ()) 4054e98e3e1Schristos frv_queue_non_implemented_instruction_interrupt (current_cpu, insn); 4064e98e3e1Schristos /* Make sure floating point support is enabled. */ 4074e98e3e1Schristos else if (! GET_H_PSR_EF ()) 4084e98e3e1Schristos { 4094e98e3e1Schristos /* Generate fp_disabled if it is a floating point insn or if PSR.EM is 4104e98e3e1Schristos off and the insns accesses a fp register. */ 4114e98e3e1Schristos if (frv_is_float_insn (insn) 4124e98e3e1Schristos || (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR_ACCESS) 4134e98e3e1Schristos && ! GET_H_PSR_EM ())) 4144e98e3e1Schristos frv_queue_float_disabled_interrupt (current_cpu); 4154e98e3e1Schristos } 4164e98e3e1Schristos /* Make sure media support is enabled. */ 4174e98e3e1Schristos else if (! GET_H_PSR_EM ()) 4184e98e3e1Schristos { 4194e98e3e1Schristos /* Generate mp_disabled if it is a media insn. */ 4204e98e3e1Schristos if (frv_is_media_insn (insn) || CGEN_INSN_NUM (insn) == FRV_INSN_MTRAP) 4214e98e3e1Schristos frv_queue_media_disabled_interrupt (current_cpu); 4224e98e3e1Schristos } 4234e98e3e1Schristos /* Check for privileged insns. */ 4244e98e3e1Schristos else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_PRIVILEGED) && 4254e98e3e1Schristos ! GET_H_PSR_S ()) 4264e98e3e1Schristos frv_queue_privileged_instruction_interrupt (current_cpu, insn); 4274e98e3e1Schristos #if 0 /* disable for now until we find out how FSR0.QNE gets reset. */ 4284e98e3e1Schristos else 4294e98e3e1Schristos { 4304e98e3e1Schristos /* Enter the halt state if FSR0.QNE is set and we are executing a 4314e98e3e1Schristos floating point insn, a media insn or an insn which access a FR 4324e98e3e1Schristos register. */ 433*854b025fSchristos SIM_DESC sd = CPU_STATE (current_cpu); 4344e98e3e1Schristos SI fsr0 = GET_FSR (0); 4354e98e3e1Schristos if (GET_FSR_QNE (fsr0) 4364e98e3e1Schristos && (frv_is_float_insn (insn) || frv_is_media_insn (insn) 4374e98e3e1Schristos || CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR_ACCESS))) 4384e98e3e1Schristos { 4394e98e3e1Schristos sim_engine_halt (sd, current_cpu, NULL, GET_H_PC (), sim_stopped, 4404e98e3e1Schristos SIM_SIGINT); 4414e98e3e1Schristos } 4424e98e3e1Schristos } 4434e98e3e1Schristos #endif 4444e98e3e1Schristos } 4454e98e3e1Schristos 4464e98e3e1Schristos /* Record the current VLIW slot in the given interrupt queue element. */ 4474e98e3e1Schristos void 4484e98e3e1Schristos frv_set_interrupt_queue_slot ( 4494e98e3e1Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item 4504e98e3e1Schristos ) 4514e98e3e1Schristos { 4524e98e3e1Schristos FRV_VLIW *vliw = CPU_VLIW (current_cpu); 4534e98e3e1Schristos int slot = vliw->next_slot - 1; 4544e98e3e1Schristos item->slot = (*vliw->current_vliw)[slot]; 4554e98e3e1Schristos } 4564e98e3e1Schristos 4574e98e3e1Schristos /* Handle an individual interrupt. */ 4584e98e3e1Schristos static void 4594e98e3e1Schristos handle_interrupt (SIM_CPU *current_cpu, IADDR pc) 4604e98e3e1Schristos { 4614e98e3e1Schristos struct frv_interrupt *interrupt; 4624e98e3e1Schristos int writeback_done = 0; 4634e98e3e1Schristos while (1) 4644e98e3e1Schristos { 4654e98e3e1Schristos /* Interrupts are queued in priority order with the highest priority 4664e98e3e1Schristos last. */ 4674e98e3e1Schristos int index = frv_interrupt_state.queue_index - 1; 4684e98e3e1Schristos struct frv_interrupt_queue_element *item 4694e98e3e1Schristos = & frv_interrupt_state.queue[index]; 4704e98e3e1Schristos interrupt = & frv_interrupt_table[item->kind]; 4714e98e3e1Schristos 4724e98e3e1Schristos switch (interrupt->iclass) 4734e98e3e1Schristos { 4744e98e3e1Schristos case FRV_EXTERNAL_INTERRUPT: 4754e98e3e1Schristos /* Perform writeback first. This may cause a higher priority 4764e98e3e1Schristos interrupt. */ 4774e98e3e1Schristos if (! writeback_done) 4784e98e3e1Schristos { 4794e98e3e1Schristos frvbf_perform_writeback (current_cpu); 4804e98e3e1Schristos writeback_done = 1; 4814e98e3e1Schristos continue; 4824e98e3e1Schristos } 4834e98e3e1Schristos frv_external_interrupt (current_cpu, item, pc); 4844e98e3e1Schristos return; 4854e98e3e1Schristos case FRV_SOFTWARE_INTERRUPT: 4864e98e3e1Schristos frv_interrupt_state.queue_index = index; 4874e98e3e1Schristos frv_software_interrupt (current_cpu, item, pc); 4884e98e3e1Schristos return; 4894e98e3e1Schristos case FRV_PROGRAM_INTERRUPT: 4904e98e3e1Schristos /* If the program interrupt is not strict (imprecise), then perform 4914e98e3e1Schristos writeback first. This may, in turn, cause a higher priority 4924e98e3e1Schristos interrupt. */ 4934e98e3e1Schristos if (! interrupt->precise && ! writeback_done) 4944e98e3e1Schristos { 4954e98e3e1Schristos frv_interrupt_state.imprecise_interrupt = item; 4964e98e3e1Schristos frvbf_perform_writeback (current_cpu); 4974e98e3e1Schristos writeback_done = 1; 4984e98e3e1Schristos continue; 4994e98e3e1Schristos } 5004e98e3e1Schristos frv_interrupt_state.queue_index = index; 5014e98e3e1Schristos frv_program_interrupt (current_cpu, item, pc); 5024e98e3e1Schristos return; 5034e98e3e1Schristos case FRV_BREAK_INTERRUPT: 5044e98e3e1Schristos frv_interrupt_state.queue_index = index; 5054e98e3e1Schristos frv_break_interrupt (current_cpu, interrupt, pc); 5064e98e3e1Schristos return; 5074e98e3e1Schristos case FRV_RESET_INTERRUPT: 5084e98e3e1Schristos break; 5094e98e3e1Schristos default: 5104e98e3e1Schristos break; 5114e98e3e1Schristos } 5124e98e3e1Schristos frv_interrupt_state.queue_index = index; 5134e98e3e1Schristos break; /* out of loop. */ 5144e98e3e1Schristos } 5154e98e3e1Schristos 5164e98e3e1Schristos /* We should never get here. */ 5174e98e3e1Schristos { 5184e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 5194e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 5204e98e3e1Schristos "interrupt class not supported %d\n", 5214e98e3e1Schristos interrupt->iclass); 5224e98e3e1Schristos } 5234e98e3e1Schristos } 5244e98e3e1Schristos 5254e98e3e1Schristos /* Check to see the if the RSTR.HR or RSTR.SR bits have been set. If so, handle 5264e98e3e1Schristos the appropriate reset interrupt. */ 5274e98e3e1Schristos static int 5284e98e3e1Schristos check_reset (SIM_CPU *current_cpu, IADDR pc) 5294e98e3e1Schristos { 5304e98e3e1Schristos int hsr0; 5314e98e3e1Schristos int hr; 5324e98e3e1Schristos int sr; 5334e98e3e1Schristos SI rstr; 5344e98e3e1Schristos FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu); 5354e98e3e1Schristos IADDR address = RSTR_ADDRESS; 5364e98e3e1Schristos 5374e98e3e1Schristos /* We don't want this to show up in the cache statistics, so read the 5384e98e3e1Schristos cache passively. */ 5394e98e3e1Schristos if (! frv_cache_read_passive_SI (cache, address, & rstr)) 5404e98e3e1Schristos rstr = sim_core_read_unaligned_4 (current_cpu, pc, read_map, address); 5414e98e3e1Schristos 5424e98e3e1Schristos hr = GET_RSTR_HR (rstr); 5434e98e3e1Schristos sr = GET_RSTR_SR (rstr); 5444e98e3e1Schristos 5454e98e3e1Schristos if (! hr && ! sr) 5464e98e3e1Schristos return 0; /* no reset. */ 5474e98e3e1Schristos 5484e98e3e1Schristos /* Reinitialize the machine state. */ 5494e98e3e1Schristos if (hr) 5504e98e3e1Schristos frv_hardware_reset (current_cpu); 5514e98e3e1Schristos else 5524e98e3e1Schristos frv_software_reset (current_cpu); 5534e98e3e1Schristos 5544e98e3e1Schristos /* Branch to the reset address. */ 5554e98e3e1Schristos hsr0 = GET_HSR0 (); 5564e98e3e1Schristos if (GET_HSR0_SA (hsr0)) 5574e98e3e1Schristos SET_H_PC (0xff000000); 5584e98e3e1Schristos else 5594e98e3e1Schristos SET_H_PC (0); 5604e98e3e1Schristos 5614e98e3e1Schristos return 1; /* reset */ 5624e98e3e1Schristos } 5634e98e3e1Schristos 5644e98e3e1Schristos /* Process any pending interrupt(s) after a group of parallel insns. */ 5654e98e3e1Schristos void 5664e98e3e1Schristos frv_process_interrupts (SIM_CPU *current_cpu) 5674e98e3e1Schristos { 5684e98e3e1Schristos SI NE_flags[2]; 5694e98e3e1Schristos /* Need to save the pc here because writeback may change it (due to a 5704e98e3e1Schristos branch). */ 5714e98e3e1Schristos IADDR pc = CPU_PC_GET (current_cpu); 5724e98e3e1Schristos 5734e98e3e1Schristos /* Check for a reset before anything else. */ 5744e98e3e1Schristos if (check_reset (current_cpu, pc)) 5754e98e3e1Schristos return; 5764e98e3e1Schristos 5774e98e3e1Schristos /* First queue the writes for any accumulated NE flags. */ 5784e98e3e1Schristos if (frv_interrupt_state.f_ne_flags[0] != 0 5794e98e3e1Schristos || frv_interrupt_state.f_ne_flags[1] != 0) 5804e98e3e1Schristos { 5814e98e3e1Schristos GET_NE_FLAGS (NE_flags, H_SPR_FNER0); 5824e98e3e1Schristos NE_flags[0] |= frv_interrupt_state.f_ne_flags[0]; 5834e98e3e1Schristos NE_flags[1] |= frv_interrupt_state.f_ne_flags[1]; 5844e98e3e1Schristos SET_NE_FLAGS (H_SPR_FNER0, NE_flags); 5854e98e3e1Schristos } 5864e98e3e1Schristos 5874e98e3e1Schristos /* If there is no interrupt pending, then perform parallel writeback. This 5884e98e3e1Schristos may cause an interrupt. */ 5894e98e3e1Schristos if (frv_interrupt_state.queue_index <= 0) 5904e98e3e1Schristos frvbf_perform_writeback (current_cpu); 5914e98e3e1Schristos 5924e98e3e1Schristos /* If there is an interrupt pending, then process it. */ 5934e98e3e1Schristos if (frv_interrupt_state.queue_index > 0) 5944e98e3e1Schristos handle_interrupt (current_cpu, pc); 5954e98e3e1Schristos } 5964e98e3e1Schristos 5974e98e3e1Schristos /* Find the next available ESR and return its index */ 5984e98e3e1Schristos static int 5994e98e3e1Schristos esr_for_data_access_exception ( 6004e98e3e1Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item 6014e98e3e1Schristos ) 6024e98e3e1Schristos { 6034e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 6044e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 6054e98e3e1Schristos return 8; /* Use ESR8, EPCR8. */ 6064e98e3e1Schristos 6074e98e3e1Schristos if (item->slot == UNIT_I0) 6084e98e3e1Schristos return 8; /* Use ESR8, EPCR8, EAR8, EDR8. */ 6094e98e3e1Schristos 6104e98e3e1Schristos return 9; /* Use ESR9, EPCR9, EAR9. */ 6114e98e3e1Schristos } 6124e98e3e1Schristos 6134e98e3e1Schristos /* Set the next available EDR register with the data which was to be stored 6144e98e3e1Schristos and return the index of the register. */ 6154e98e3e1Schristos static int 6164e98e3e1Schristos set_edr_register ( 6174e98e3e1Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, int edr_index 6184e98e3e1Schristos ) 6194e98e3e1Schristos { 6204e98e3e1Schristos /* EDR0, EDR4 and EDR8 are available as blocks of 4. 6214e98e3e1Schristos SI data uses EDR3, EDR7 and EDR11 6224e98e3e1Schristos DI data uses EDR2, EDR6 and EDR10 6234e98e3e1Schristos XI data uses EDR0, EDR4 and EDR8. */ 6244e98e3e1Schristos int i; 6254e98e3e1Schristos edr_index += 4 - item->u.data_written.length; 6264e98e3e1Schristos for (i = 0; i < item->u.data_written.length; ++i) 6274e98e3e1Schristos SET_EDR (edr_index + i, item->u.data_written.words[i]); 6284e98e3e1Schristos 6294e98e3e1Schristos return edr_index; 6304e98e3e1Schristos }; 6314e98e3e1Schristos 6324e98e3e1Schristos /* Clear ESFR0, EPCRx, ESRx, EARx and EDRx. */ 6334e98e3e1Schristos static void 6344e98e3e1Schristos clear_exception_status_registers (SIM_CPU *current_cpu) 6354e98e3e1Schristos { 6364e98e3e1Schristos int i; 6374e98e3e1Schristos /* It is only necessary to clear the flag bits indicating which registers 6384e98e3e1Schristos are valid. */ 6394e98e3e1Schristos SET_ESFR (0, 0); 6404e98e3e1Schristos SET_ESFR (1, 0); 6414e98e3e1Schristos 6424e98e3e1Schristos for (i = 0; i <= 2; ++i) 6434e98e3e1Schristos { 6444e98e3e1Schristos SI esr = GET_ESR (i); 6454e98e3e1Schristos CLEAR_ESR_VALID (esr); 6464e98e3e1Schristos SET_ESR (i, esr); 6474e98e3e1Schristos } 6484e98e3e1Schristos for (i = 8; i <= 15; ++i) 6494e98e3e1Schristos { 6504e98e3e1Schristos SI esr = GET_ESR (i); 6514e98e3e1Schristos CLEAR_ESR_VALID (esr); 6524e98e3e1Schristos SET_ESR (i, esr); 6534e98e3e1Schristos } 6544e98e3e1Schristos } 6554e98e3e1Schristos 6564e98e3e1Schristos /* Record state for media exception. */ 6574e98e3e1Schristos void 6584e98e3e1Schristos frv_set_mp_exception_registers ( 6594e98e3e1Schristos SIM_CPU *current_cpu, enum frv_msr_mtt mtt, int sie 6604e98e3e1Schristos ) 6614e98e3e1Schristos { 6624e98e3e1Schristos /* Record the interrupt factor in MSR0. */ 6634e98e3e1Schristos SI msr0 = GET_MSR (0); 6644e98e3e1Schristos if (GET_MSR_MTT (msr0) == MTT_NONE) 6654e98e3e1Schristos SET_MSR_MTT (msr0, mtt); 6664e98e3e1Schristos 6674e98e3e1Schristos /* Also set the OVF bit in the appropriate MSR as well as MSR0.AOVF. */ 6684e98e3e1Schristos if (mtt == MTT_OVERFLOW) 6694e98e3e1Schristos { 6704e98e3e1Schristos FRV_VLIW *vliw = CPU_VLIW (current_cpu); 6714e98e3e1Schristos int slot = vliw->next_slot - 1; 6724e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 6734e98e3e1Schristos 6744e98e3e1Schristos /* If this insn is in the M2 slot, then set MSR1.OVF and MSR1.SIE, 6754e98e3e1Schristos otherwise set MSR0.OVF and MSR0.SIE. */ 6764e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550 && (*vliw->current_vliw)[slot] == UNIT_FM1) 6774e98e3e1Schristos { 6784e98e3e1Schristos SI msr = GET_MSR (1); 6794e98e3e1Schristos OR_MSR_SIE (msr, sie); 6804e98e3e1Schristos SET_MSR_OVF (msr); 6814e98e3e1Schristos SET_MSR (1, msr); 6824e98e3e1Schristos } 6834e98e3e1Schristos else 6844e98e3e1Schristos { 6854e98e3e1Schristos OR_MSR_SIE (msr0, sie); 6864e98e3e1Schristos SET_MSR_OVF (msr0); 6874e98e3e1Schristos } 6884e98e3e1Schristos 6894e98e3e1Schristos /* Generate the interrupt now if MSR0.MPEM is set on fr550 */ 6904e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550 && GET_MSR_MPEM (msr0)) 6914e98e3e1Schristos frv_queue_program_interrupt (current_cpu, FRV_MP_EXCEPTION); 6924e98e3e1Schristos else 6934e98e3e1Schristos { 6944e98e3e1Schristos /* Regardless of the slot, set MSR0.AOVF. */ 6954e98e3e1Schristos SET_MSR_AOVF (msr0); 6964e98e3e1Schristos } 6974e98e3e1Schristos } 6984e98e3e1Schristos 6994e98e3e1Schristos SET_MSR (0, msr0); 7004e98e3e1Schristos } 7014e98e3e1Schristos 7024e98e3e1Schristos /* Determine the correct FQ register to use for the given exception. 7034e98e3e1Schristos Return -1 if a register is not available. */ 7044e98e3e1Schristos static int 7054e98e3e1Schristos fq_for_exception ( 7064e98e3e1Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item 7074e98e3e1Schristos ) 7084e98e3e1Schristos { 7094e98e3e1Schristos SI fq; 7104e98e3e1Schristos struct frv_fp_exception_info *fp_info = & item->u.fp_info; 7114e98e3e1Schristos 7124e98e3e1Schristos /* For fp_exception overflow, underflow or inexact, use FQ0 or FQ1. */ 7134e98e3e1Schristos if (fp_info->ftt == FTT_IEEE_754_EXCEPTION 7144e98e3e1Schristos && (fp_info->fsr_mask & (FSR_OVERFLOW | FSR_UNDERFLOW | FSR_INEXACT))) 7154e98e3e1Schristos { 7164e98e3e1Schristos fq = GET_FQ (0); 7174e98e3e1Schristos if (! GET_FQ_VALID (fq)) 7184e98e3e1Schristos return 0; /* FQ0 is available. */ 7194e98e3e1Schristos fq = GET_FQ (1); 7204e98e3e1Schristos if (! GET_FQ_VALID (fq)) 7214e98e3e1Schristos return 1; /* FQ1 is available. */ 7224e98e3e1Schristos 7234e98e3e1Schristos /* No FQ register is available */ 7244e98e3e1Schristos { 7254e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 7264e98e3e1Schristos IADDR pc = CPU_PC_GET (current_cpu); 7274e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, "No FQ register available\n"); 7284e98e3e1Schristos } 7294e98e3e1Schristos return -1; 7304e98e3e1Schristos } 7314e98e3e1Schristos /* For other exceptions, use FQ2 if the insn was in slot F0/I0 and FQ3 7324e98e3e1Schristos otherwise. */ 7334e98e3e1Schristos if (item->slot == UNIT_FM0 || item->slot == UNIT_I0) 7344e98e3e1Schristos return 2; 7354e98e3e1Schristos 7364e98e3e1Schristos return 3; 7374e98e3e1Schristos } 7384e98e3e1Schristos 7394e98e3e1Schristos /* Set FSR0, FQ0-FQ9, depending on the interrupt. */ 7404e98e3e1Schristos static void 7414e98e3e1Schristos set_fp_exception_registers ( 7424e98e3e1Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item 7434e98e3e1Schristos ) 7444e98e3e1Schristos { 7454e98e3e1Schristos int fq_index; 7464e98e3e1Schristos SI fq; 7474e98e3e1Schristos SI insn; 7484e98e3e1Schristos SI fsr0; 7494e98e3e1Schristos IADDR pc; 7504e98e3e1Schristos struct frv_fp_exception_info *fp_info; 7514e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 7524e98e3e1Schristos 7534e98e3e1Schristos /* No FQ registers on fr550 */ 7544e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 7554e98e3e1Schristos { 7564e98e3e1Schristos /* Update the fsr. */ 7574e98e3e1Schristos fp_info = & item->u.fp_info; 7584e98e3e1Schristos fsr0 = GET_FSR (0); 7594e98e3e1Schristos SET_FSR_FTT (fsr0, fp_info->ftt); 7604e98e3e1Schristos SET_FSR (0, fsr0); 7614e98e3e1Schristos return; 7624e98e3e1Schristos } 7634e98e3e1Schristos 7644e98e3e1Schristos /* Select an FQ and update it with the exception information. */ 7654e98e3e1Schristos fq_index = fq_for_exception (current_cpu, item); 7664e98e3e1Schristos if (fq_index == -1) 7674e98e3e1Schristos return; 7684e98e3e1Schristos 7694e98e3e1Schristos fp_info = & item->u.fp_info; 7704e98e3e1Schristos fq = GET_FQ (fq_index); 7714e98e3e1Schristos SET_FQ_MIV (fq, MIV_FLOAT); 7724e98e3e1Schristos SET_FQ_SIE (fq, SIE_NIL); 7734e98e3e1Schristos SET_FQ_FTT (fq, fp_info->ftt); 7744e98e3e1Schristos SET_FQ_CEXC (fq, fp_info->fsr_mask); 7754e98e3e1Schristos SET_FQ_VALID (fq); 7764e98e3e1Schristos SET_FQ (fq_index, fq); 7774e98e3e1Schristos 7784e98e3e1Schristos /* Write the failing insn into FQx.OPC. */ 7794e98e3e1Schristos pc = item->vpc; 7804e98e3e1Schristos insn = GETMEMSI (current_cpu, pc, pc); 7814e98e3e1Schristos SET_FQ_OPC (fq_index, insn); 7824e98e3e1Schristos 7834e98e3e1Schristos /* Update the fsr. */ 7844e98e3e1Schristos fsr0 = GET_FSR (0); 7854e98e3e1Schristos SET_FSR_QNE (fsr0); /* FQ not empty */ 7864e98e3e1Schristos SET_FSR_FTT (fsr0, fp_info->ftt); 7874e98e3e1Schristos SET_FSR (0, fsr0); 7884e98e3e1Schristos } 7894e98e3e1Schristos 7904e98e3e1Schristos /* Record the state of a division exception in the ISR. */ 7914e98e3e1Schristos static void 7924e98e3e1Schristos set_isr_exception_fields ( 7934e98e3e1Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item 7944e98e3e1Schristos ) 7954e98e3e1Schristos { 7964e98e3e1Schristos USI isr = GET_ISR (); 7974e98e3e1Schristos int dtt = GET_ISR_DTT (isr); 7984e98e3e1Schristos dtt |= item->u.dtt; 7994e98e3e1Schristos SET_ISR_DTT (isr, dtt); 8004e98e3e1Schristos SET_ISR (isr); 8014e98e3e1Schristos } 8024e98e3e1Schristos 8034e98e3e1Schristos /* Set ESFR0, EPCRx, ESRx, EARx and EDRx, according to the given program 8044e98e3e1Schristos interrupt. */ 8054e98e3e1Schristos static void 8064e98e3e1Schristos set_exception_status_registers ( 8074e98e3e1Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item 8084e98e3e1Schristos ) 8094e98e3e1Schristos { 8104e98e3e1Schristos struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind]; 8114e98e3e1Schristos int reg_index = -1; 8124e98e3e1Schristos int set_ear = 0; 8134e98e3e1Schristos int set_edr = 0; 8144e98e3e1Schristos int set_daec = 0; 8154e98e3e1Schristos int set_epcr = 0; 8164e98e3e1Schristos SI esr = 0; 8174e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 8184e98e3e1Schristos 8194e98e3e1Schristos /* If the interrupt is strict (precise) or the interrupt is on the insns 8204e98e3e1Schristos in the I0 pipe, then set the 0 registers. */ 8214e98e3e1Schristos if (interrupt->precise) 8224e98e3e1Schristos { 8234e98e3e1Schristos reg_index = 0; 8244e98e3e1Schristos if (interrupt->kind == FRV_REGISTER_EXCEPTION) 8254e98e3e1Schristos SET_ESR_REC (esr, item->u.rec); 8264e98e3e1Schristos else if (interrupt->kind == FRV_INSTRUCTION_ACCESS_EXCEPTION) 8274e98e3e1Schristos SET_ESR_IAEC (esr, item->u.iaec); 8284e98e3e1Schristos /* For fr550, don't set epcr for precise interrupts. */ 8294e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550) 8304e98e3e1Schristos set_epcr = 1; 8314e98e3e1Schristos } 8324e98e3e1Schristos else 8334e98e3e1Schristos { 8344e98e3e1Schristos switch (interrupt->kind) 8354e98e3e1Schristos { 8364e98e3e1Schristos case FRV_DIVISION_EXCEPTION: 8374e98e3e1Schristos set_isr_exception_fields (current_cpu, item); 838*854b025fSchristos ATTRIBUTE_FALLTHROUGH; /* To set reg_index. */ 8394e98e3e1Schristos case FRV_COMMIT_EXCEPTION: 8404e98e3e1Schristos /* For fr550, always use ESR0. */ 8414e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 8424e98e3e1Schristos reg_index = 0; 8434e98e3e1Schristos else if (item->slot == UNIT_I0) 8444e98e3e1Schristos reg_index = 0; 8454e98e3e1Schristos else if (item->slot == UNIT_I1) 8464e98e3e1Schristos reg_index = 1; 8474e98e3e1Schristos set_epcr = 1; 8484e98e3e1Schristos break; 8494e98e3e1Schristos case FRV_DATA_STORE_ERROR: 8504e98e3e1Schristos reg_index = 14; /* Use ESR14. */ 8514e98e3e1Schristos break; 8524e98e3e1Schristos case FRV_DATA_ACCESS_ERROR: 8534e98e3e1Schristos reg_index = 15; /* Use ESR15, EPCR15. */ 8544e98e3e1Schristos set_ear = 1; 8554e98e3e1Schristos break; 8564e98e3e1Schristos case FRV_DATA_ACCESS_EXCEPTION: 8574e98e3e1Schristos set_daec = 1; 858*854b025fSchristos ATTRIBUTE_FALLTHROUGH; 8594e98e3e1Schristos case FRV_DATA_ACCESS_MMU_MISS: 8604e98e3e1Schristos case FRV_MEM_ADDRESS_NOT_ALIGNED: 8614e98e3e1Schristos /* Get the appropriate ESR, EPCR, EAR and EDR. 8624e98e3e1Schristos EAR will be set. EDR will not be set if this is a store insn. */ 8634e98e3e1Schristos set_ear = 1; 8644e98e3e1Schristos /* For fr550, never use EDRx. */ 8654e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550) 8664e98e3e1Schristos if (item->u.data_written.length != 0) 8674e98e3e1Schristos set_edr = 1; 8684e98e3e1Schristos reg_index = esr_for_data_access_exception (current_cpu, item); 8694e98e3e1Schristos set_epcr = 1; 8704e98e3e1Schristos break; 8714e98e3e1Schristos case FRV_MP_EXCEPTION: 8724e98e3e1Schristos /* For fr550, use EPCR2 and ESR2. */ 8734e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 8744e98e3e1Schristos { 8754e98e3e1Schristos reg_index = 2; 8764e98e3e1Schristos set_epcr = 1; 8774e98e3e1Schristos } 8784e98e3e1Schristos break; /* MSR0-1, FQ0-9 are already set. */ 8794e98e3e1Schristos case FRV_FP_EXCEPTION: 8804e98e3e1Schristos set_fp_exception_registers (current_cpu, item); 8814e98e3e1Schristos /* For fr550, use EPCR2 and ESR2. */ 8824e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 8834e98e3e1Schristos { 8844e98e3e1Schristos reg_index = 2; 8854e98e3e1Schristos set_epcr = 1; 8864e98e3e1Schristos } 8874e98e3e1Schristos break; 8884e98e3e1Schristos default: 8894e98e3e1Schristos { 8904e98e3e1Schristos IADDR pc = CPU_PC_GET (current_cpu); 8914e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 8924e98e3e1Schristos "invalid non-strict program interrupt kind: %d\n", 8934e98e3e1Schristos interrupt->kind); 8944e98e3e1Schristos break; 8954e98e3e1Schristos } 8964e98e3e1Schristos } 8974e98e3e1Schristos } /* non-strict (imprecise) interrupt */ 8984e98e3e1Schristos 8994e98e3e1Schristos /* Now fill in the selected exception status registers. */ 9004e98e3e1Schristos if (reg_index != -1) 9014e98e3e1Schristos { 9024e98e3e1Schristos /* Now set the exception status registers. */ 9034e98e3e1Schristos SET_ESFR_FLAG (reg_index); 9044e98e3e1Schristos SET_ESR_EC (esr, interrupt->ec); 9054e98e3e1Schristos 9064e98e3e1Schristos if (set_epcr) 9074e98e3e1Schristos { 9084e98e3e1Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400) 9094e98e3e1Schristos SET_EPCR (reg_index, previous_vliw_pc); 9104e98e3e1Schristos else 9114e98e3e1Schristos SET_EPCR (reg_index, item->vpc); 9124e98e3e1Schristos } 9134e98e3e1Schristos 9144e98e3e1Schristos if (set_ear) 9154e98e3e1Schristos { 9164e98e3e1Schristos SET_EAR (reg_index, item->eaddress); 9174e98e3e1Schristos SET_ESR_EAV (esr); 9184e98e3e1Schristos } 9194e98e3e1Schristos else 9204e98e3e1Schristos CLEAR_ESR_EAV (esr); 9214e98e3e1Schristos 9224e98e3e1Schristos if (set_edr) 9234e98e3e1Schristos { 9244e98e3e1Schristos int edn = set_edr_register (current_cpu, item, 0/* EDR0-3 */); 9254e98e3e1Schristos SET_ESR_EDN (esr, edn); 9264e98e3e1Schristos SET_ESR_EDV (esr); 9274e98e3e1Schristos } 9284e98e3e1Schristos else 9294e98e3e1Schristos CLEAR_ESR_EDV (esr); 9304e98e3e1Schristos 9314e98e3e1Schristos if (set_daec) 9324e98e3e1Schristos SET_ESR_DAEC (esr, item->u.daec); 9334e98e3e1Schristos 9344e98e3e1Schristos SET_ESR_VALID (esr); 9354e98e3e1Schristos SET_ESR (reg_index, esr); 9364e98e3e1Schristos } 9374e98e3e1Schristos } 9384e98e3e1Schristos 9394e98e3e1Schristos /* Check for compound interrupts. 9404e98e3e1Schristos Returns NULL if no interrupt is to be processed. */ 9414e98e3e1Schristos static struct frv_interrupt * 9424e98e3e1Schristos check_for_compound_interrupt ( 9434e98e3e1Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item 9444e98e3e1Schristos ) 9454e98e3e1Schristos { 9464e98e3e1Schristos struct frv_interrupt *interrupt; 9474e98e3e1Schristos 9484e98e3e1Schristos /* Set the exception status registers for the original interrupt. */ 9494e98e3e1Schristos set_exception_status_registers (current_cpu, item); 9504e98e3e1Schristos interrupt = & frv_interrupt_table[item->kind]; 9514e98e3e1Schristos 9524e98e3e1Schristos if (! interrupt->precise) 9534e98e3e1Schristos { 9544e98e3e1Schristos IADDR vpc = 0; 9554e98e3e1Schristos int mask = 0; 9564e98e3e1Schristos 9574e98e3e1Schristos vpc = item->vpc; 9584e98e3e1Schristos mask = (1 << item->kind); 9594e98e3e1Schristos 9604e98e3e1Schristos /* Look for more queued program interrupts which are non-deferred 9614e98e3e1Schristos (pending inhibit), imprecise (non-strict) different than an interrupt 9624e98e3e1Schristos already found and caused by a different insn. A bit mask is used 9634e98e3e1Schristos to keep track of interrupts which have already been detected. */ 9644e98e3e1Schristos while (item != frv_interrupt_state.queue) 9654e98e3e1Schristos { 9664e98e3e1Schristos enum frv_interrupt_kind kind; 9674e98e3e1Schristos struct frv_interrupt *next_interrupt; 9684e98e3e1Schristos --item; 9694e98e3e1Schristos kind = item->kind; 9704e98e3e1Schristos next_interrupt = & frv_interrupt_table[kind]; 9714e98e3e1Schristos 9724e98e3e1Schristos if (next_interrupt->iclass != FRV_PROGRAM_INTERRUPT) 9734e98e3e1Schristos break; /* no program interrupts left. */ 9744e98e3e1Schristos 9754e98e3e1Schristos if (item->vpc == vpc) 9764e98e3e1Schristos continue; /* caused by the same insn. */ 9774e98e3e1Schristos 9784e98e3e1Schristos vpc = item->vpc; 9794e98e3e1Schristos if (! next_interrupt->precise && ! next_interrupt->deferred) 9804e98e3e1Schristos { 9814e98e3e1Schristos if (! (mask & (1 << kind))) 9824e98e3e1Schristos { 9834e98e3e1Schristos /* Set the exception status registers for the additional 9844e98e3e1Schristos interrupt. */ 9854e98e3e1Schristos set_exception_status_registers (current_cpu, item); 9864e98e3e1Schristos mask |= (1 << kind); 9874e98e3e1Schristos interrupt = & frv_interrupt_table[FRV_COMPOUND_EXCEPTION]; 9884e98e3e1Schristos } 9894e98e3e1Schristos } 9904e98e3e1Schristos } 9914e98e3e1Schristos } 9924e98e3e1Schristos 9934e98e3e1Schristos /* Return with either the original interrupt, a compound_exception, 9944e98e3e1Schristos or no exception. */ 9954e98e3e1Schristos return interrupt; 9964e98e3e1Schristos } 9974e98e3e1Schristos 9984e98e3e1Schristos /* Handle a program interrupt. */ 9994e98e3e1Schristos void 10004e98e3e1Schristos frv_program_interrupt ( 10014e98e3e1Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc 10024e98e3e1Schristos ) 10034e98e3e1Schristos { 10044e98e3e1Schristos struct frv_interrupt *interrupt; 10054e98e3e1Schristos 10064e98e3e1Schristos clear_exception_status_registers (current_cpu); 10074e98e3e1Schristos /* If two or more non-deferred imprecise (non-strict) interrupts occur 10084e98e3e1Schristos on two or more insns, then generate a compound_exception. */ 10094e98e3e1Schristos interrupt = check_for_compound_interrupt (current_cpu, item); 10104e98e3e1Schristos if (interrupt != NULL) 10114e98e3e1Schristos { 10124e98e3e1Schristos frv_program_or_software_interrupt (current_cpu, interrupt, pc); 10134e98e3e1Schristos frv_clear_interrupt_classes (FRV_SOFTWARE_INTERRUPT, 10144e98e3e1Schristos FRV_PROGRAM_INTERRUPT); 10154e98e3e1Schristos } 10164e98e3e1Schristos } 10174e98e3e1Schristos 10184e98e3e1Schristos /* Handle a software interrupt. */ 10194e98e3e1Schristos void 10204e98e3e1Schristos frv_software_interrupt ( 10214e98e3e1Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc 10224e98e3e1Schristos ) 10234e98e3e1Schristos { 10244e98e3e1Schristos struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind]; 10254e98e3e1Schristos frv_program_or_software_interrupt (current_cpu, interrupt, pc); 10264e98e3e1Schristos } 10274e98e3e1Schristos 10284e98e3e1Schristos /* Handle a program interrupt or a software interrupt in non-operating mode. */ 10294e98e3e1Schristos void 10304e98e3e1Schristos frv_non_operating_interrupt ( 10314e98e3e1Schristos SIM_CPU *current_cpu, enum frv_interrupt_kind kind, IADDR pc 10324e98e3e1Schristos ) 10334e98e3e1Schristos { 10344e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 10354e98e3e1Schristos switch (kind) 10364e98e3e1Schristos { 10374e98e3e1Schristos case FRV_INTERRUPT_LEVEL_1: 10384e98e3e1Schristos case FRV_INTERRUPT_LEVEL_2: 10394e98e3e1Schristos case FRV_INTERRUPT_LEVEL_3: 10404e98e3e1Schristos case FRV_INTERRUPT_LEVEL_4: 10414e98e3e1Schristos case FRV_INTERRUPT_LEVEL_5: 10424e98e3e1Schristos case FRV_INTERRUPT_LEVEL_6: 10434e98e3e1Schristos case FRV_INTERRUPT_LEVEL_7: 10444e98e3e1Schristos case FRV_INTERRUPT_LEVEL_8: 10454e98e3e1Schristos case FRV_INTERRUPT_LEVEL_9: 10464e98e3e1Schristos case FRV_INTERRUPT_LEVEL_10: 10474e98e3e1Schristos case FRV_INTERRUPT_LEVEL_11: 10484e98e3e1Schristos case FRV_INTERRUPT_LEVEL_12: 10494e98e3e1Schristos case FRV_INTERRUPT_LEVEL_13: 10504e98e3e1Schristos case FRV_INTERRUPT_LEVEL_14: 10514e98e3e1Schristos case FRV_INTERRUPT_LEVEL_15: 10524e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 10534e98e3e1Schristos "interrupt: external %d\n", kind + 1); 10544e98e3e1Schristos break; 10554e98e3e1Schristos case FRV_TRAP_INSTRUCTION: 10564e98e3e1Schristos break; /* handle as in operating mode. */ 10574e98e3e1Schristos case FRV_COMMIT_EXCEPTION: 10584e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 10594e98e3e1Schristos "interrupt: commit_exception\n"); 10604e98e3e1Schristos break; 10614e98e3e1Schristos case FRV_DIVISION_EXCEPTION: 10624e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 10634e98e3e1Schristos "interrupt: division_exception\n"); 10644e98e3e1Schristos break; 10654e98e3e1Schristos case FRV_DATA_STORE_ERROR: 10664e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 10674e98e3e1Schristos "interrupt: data_store_error\n"); 10684e98e3e1Schristos break; 10694e98e3e1Schristos case FRV_DATA_ACCESS_EXCEPTION: 10704e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 10714e98e3e1Schristos "interrupt: data_access_exception\n"); 10724e98e3e1Schristos break; 10734e98e3e1Schristos case FRV_DATA_ACCESS_MMU_MISS: 10744e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 10754e98e3e1Schristos "interrupt: data_access_mmu_miss\n"); 10764e98e3e1Schristos break; 10774e98e3e1Schristos case FRV_DATA_ACCESS_ERROR: 10784e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 10794e98e3e1Schristos "interrupt: data_access_error\n"); 10804e98e3e1Schristos break; 10814e98e3e1Schristos case FRV_MP_EXCEPTION: 10824e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 10834e98e3e1Schristos "interrupt: mp_exception\n"); 10844e98e3e1Schristos break; 10854e98e3e1Schristos case FRV_FP_EXCEPTION: 10864e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 10874e98e3e1Schristos "interrupt: fp_exception\n"); 10884e98e3e1Schristos break; 10894e98e3e1Schristos case FRV_MEM_ADDRESS_NOT_ALIGNED: 10904e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 10914e98e3e1Schristos "interrupt: mem_address_not_aligned\n"); 10924e98e3e1Schristos break; 10934e98e3e1Schristos case FRV_REGISTER_EXCEPTION: 10944e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 10954e98e3e1Schristos "interrupt: register_exception\n"); 10964e98e3e1Schristos break; 10974e98e3e1Schristos case FRV_MP_DISABLED: 10984e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 10994e98e3e1Schristos "interrupt: mp_disabled\n"); 11004e98e3e1Schristos break; 11014e98e3e1Schristos case FRV_FP_DISABLED: 11024e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 11034e98e3e1Schristos "interrupt: fp_disabled\n"); 11044e98e3e1Schristos break; 11054e98e3e1Schristos case FRV_PRIVILEGED_INSTRUCTION: 11064e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 11074e98e3e1Schristos "interrupt: privileged_instruction\n"); 11084e98e3e1Schristos break; 11094e98e3e1Schristos case FRV_ILLEGAL_INSTRUCTION: 11104e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 11114e98e3e1Schristos "interrupt: illegal_instruction\n"); 11124e98e3e1Schristos break; 11134e98e3e1Schristos case FRV_INSTRUCTION_ACCESS_EXCEPTION: 11144e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 11154e98e3e1Schristos "interrupt: instruction_access_exception\n"); 11164e98e3e1Schristos break; 11174e98e3e1Schristos case FRV_INSTRUCTION_ACCESS_MMU_MISS: 11184e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 11194e98e3e1Schristos "interrupt: instruction_access_mmu_miss\n"); 11204e98e3e1Schristos break; 11214e98e3e1Schristos case FRV_INSTRUCTION_ACCESS_ERROR: 11224e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 11234e98e3e1Schristos "interrupt: insn_access_error\n"); 11244e98e3e1Schristos break; 11254e98e3e1Schristos case FRV_COMPOUND_EXCEPTION: 11264e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 11274e98e3e1Schristos "interrupt: compound_exception\n"); 11284e98e3e1Schristos break; 11294e98e3e1Schristos case FRV_BREAK_EXCEPTION: 11304e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 11314e98e3e1Schristos "interrupt: break_exception\n"); 11324e98e3e1Schristos break; 11334e98e3e1Schristos case FRV_RESET: 11344e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 11354e98e3e1Schristos "interrupt: reset\n"); 11364e98e3e1Schristos break; 11374e98e3e1Schristos default: 11384e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 11394e98e3e1Schristos "unhandled interrupt kind: %d\n", kind); 11404e98e3e1Schristos break; 11414e98e3e1Schristos } 11424e98e3e1Schristos } 11434e98e3e1Schristos 11444e98e3e1Schristos /* Handle a break interrupt. */ 11454e98e3e1Schristos void 11464e98e3e1Schristos frv_break_interrupt ( 11474e98e3e1Schristos SIM_CPU *current_cpu, struct frv_interrupt *interrupt, IADDR current_pc 11484e98e3e1Schristos ) 11494e98e3e1Schristos { 11504e98e3e1Schristos IADDR new_pc; 11514e98e3e1Schristos 11524e98e3e1Schristos /* BPCSR=PC 11534e98e3e1Schristos BPSR.BS=PSR.S 11544e98e3e1Schristos BPSR.BET=PSR.ET 11554e98e3e1Schristos PSR.S=1 11564e98e3e1Schristos PSR.ET=0 11574e98e3e1Schristos TBR.TT=0xff 11584e98e3e1Schristos PC=TBR 11594e98e3e1Schristos */ 11604e98e3e1Schristos /* Must set PSR.S first to allow access to supervisor-only spr registers. */ 11614e98e3e1Schristos SET_H_BPSR_BS (GET_H_PSR_S ()); 11624e98e3e1Schristos SET_H_BPSR_BET (GET_H_PSR_ET ()); 11634e98e3e1Schristos SET_H_PSR_S (1); 11644e98e3e1Schristos SET_H_PSR_ET (0); 11654e98e3e1Schristos /* Must set PSR.S first to allow access to supervisor-only spr registers. */ 11664e98e3e1Schristos SET_H_SPR (H_SPR_BPCSR, current_pc); 11674e98e3e1Schristos 11684e98e3e1Schristos /* Set the new PC in the TBR. */ 11694e98e3e1Schristos SET_H_TBR_TT (interrupt->handler_offset); 11704e98e3e1Schristos new_pc = GET_H_SPR (H_SPR_TBR); 11714e98e3e1Schristos SET_H_PC (new_pc); 11724e98e3e1Schristos 11734e98e3e1Schristos CPU_DEBUG_STATE (current_cpu) = 1; 11744e98e3e1Schristos } 11754e98e3e1Schristos 11764e98e3e1Schristos /* Handle a program interrupt or a software interrupt. */ 11774e98e3e1Schristos void 11784e98e3e1Schristos frv_program_or_software_interrupt ( 11794e98e3e1Schristos SIM_CPU *current_cpu, struct frv_interrupt *interrupt, IADDR current_pc 11804e98e3e1Schristos ) 11814e98e3e1Schristos { 11824e98e3e1Schristos USI new_pc; 11834e98e3e1Schristos int original_psr_et; 11844e98e3e1Schristos 11854e98e3e1Schristos /* PCSR=PC 11864e98e3e1Schristos PSR.PS=PSR.S 11874e98e3e1Schristos PSR.ET=0 11884e98e3e1Schristos PSR.S=1 11894e98e3e1Schristos if PSR.ESR==1 11904e98e3e1Schristos SR0 through SR3=GR4 through GR7 11914e98e3e1Schristos TBR.TT=interrupt handler offset 11924e98e3e1Schristos PC=TBR 11934e98e3e1Schristos */ 11944e98e3e1Schristos original_psr_et = GET_H_PSR_ET (); 11954e98e3e1Schristos 11964e98e3e1Schristos SET_H_PSR_PS (GET_H_PSR_S ()); 11974e98e3e1Schristos SET_H_PSR_ET (0); 11984e98e3e1Schristos SET_H_PSR_S (1); 11994e98e3e1Schristos 12004e98e3e1Schristos /* Must set PSR.S first to allow access to supervisor-only spr registers. */ 12014e98e3e1Schristos /* The PCSR depends on the precision of the interrupt. */ 12024e98e3e1Schristos if (interrupt->precise) 12034e98e3e1Schristos SET_H_SPR (H_SPR_PCSR, previous_vliw_pc); 12044e98e3e1Schristos else 12054e98e3e1Schristos SET_H_SPR (H_SPR_PCSR, current_pc); 12064e98e3e1Schristos 12074e98e3e1Schristos /* Set the new PC in the TBR. */ 12084e98e3e1Schristos SET_H_TBR_TT (interrupt->handler_offset); 12094e98e3e1Schristos new_pc = GET_H_SPR (H_SPR_TBR); 12104e98e3e1Schristos SET_H_PC (new_pc); 12114e98e3e1Schristos 12124e98e3e1Schristos /* If PSR.ET was not originally set, then enter the stopped state. */ 12134e98e3e1Schristos if (! original_psr_et) 12144e98e3e1Schristos { 12154e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 12164e98e3e1Schristos frv_non_operating_interrupt (current_cpu, interrupt->kind, current_pc); 12174e98e3e1Schristos sim_engine_halt (sd, current_cpu, NULL, new_pc, sim_stopped, SIM_SIGINT); 12184e98e3e1Schristos } 12194e98e3e1Schristos } 12204e98e3e1Schristos 12214e98e3e1Schristos /* Handle a program interrupt or a software interrupt. */ 12224e98e3e1Schristos void 12234e98e3e1Schristos frv_external_interrupt ( 12244e98e3e1Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc 12254e98e3e1Schristos ) 12264e98e3e1Schristos { 12274e98e3e1Schristos USI new_pc; 12284e98e3e1Schristos struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind]; 12294e98e3e1Schristos 12304e98e3e1Schristos /* Don't process the interrupt if PSR.ET is not set or if it is masked. 12314e98e3e1Schristos Interrupt 15 is processed even if it appears to be masked. */ 12324e98e3e1Schristos if (! GET_H_PSR_ET () 12334e98e3e1Schristos || (interrupt->kind != FRV_INTERRUPT_LEVEL_15 12344e98e3e1Schristos && interrupt->kind < GET_H_PSR_PIL ())) 12354e98e3e1Schristos return; /* Leave it for later. */ 12364e98e3e1Schristos 12374e98e3e1Schristos /* Remove the interrupt from the queue. */ 12384e98e3e1Schristos --frv_interrupt_state.queue_index; 12394e98e3e1Schristos 12404e98e3e1Schristos /* PCSR=PC 12414e98e3e1Schristos PSR.PS=PSR.S 12424e98e3e1Schristos PSR.ET=0 12434e98e3e1Schristos PSR.S=1 12444e98e3e1Schristos if PSR.ESR==1 12454e98e3e1Schristos SR0 through SR3=GR4 through GR7 12464e98e3e1Schristos TBR.TT=interrupt handler offset 12474e98e3e1Schristos PC=TBR 12484e98e3e1Schristos */ 12494e98e3e1Schristos SET_H_PSR_PS (GET_H_PSR_S ()); 12504e98e3e1Schristos SET_H_PSR_ET (0); 12514e98e3e1Schristos SET_H_PSR_S (1); 12524e98e3e1Schristos /* Must set PSR.S first to allow access to supervisor-only spr registers. */ 12534e98e3e1Schristos SET_H_SPR (H_SPR_PCSR, GET_H_PC ()); 12544e98e3e1Schristos 12554e98e3e1Schristos /* Set the new PC in the TBR. */ 12564e98e3e1Schristos SET_H_TBR_TT (interrupt->handler_offset); 12574e98e3e1Schristos new_pc = GET_H_SPR (H_SPR_TBR); 12584e98e3e1Schristos SET_H_PC (new_pc); 12594e98e3e1Schristos } 12604e98e3e1Schristos 12614e98e3e1Schristos /* Clear interrupts which fall within the range of classes given. */ 12624e98e3e1Schristos void 12634e98e3e1Schristos frv_clear_interrupt_classes ( 12644e98e3e1Schristos enum frv_interrupt_class low_class, enum frv_interrupt_class high_class 12654e98e3e1Schristos ) 12664e98e3e1Schristos { 12674e98e3e1Schristos int i; 12684e98e3e1Schristos int j; 12694e98e3e1Schristos int limit = frv_interrupt_state.queue_index; 12704e98e3e1Schristos 12714e98e3e1Schristos /* Find the lowest priority interrupt to be removed. */ 12724e98e3e1Schristos for (i = 0; i < limit; ++i) 12734e98e3e1Schristos { 12744e98e3e1Schristos enum frv_interrupt_kind kind = frv_interrupt_state.queue[i].kind; 12754e98e3e1Schristos struct frv_interrupt* interrupt = & frv_interrupt_table[kind]; 12764e98e3e1Schristos if (interrupt->iclass >= low_class) 12774e98e3e1Schristos break; 12784e98e3e1Schristos } 12794e98e3e1Schristos 12804e98e3e1Schristos /* Find the highest priority interrupt to be removed. */ 12814e98e3e1Schristos for (j = limit - 1; j >= i; --j) 12824e98e3e1Schristos { 12834e98e3e1Schristos enum frv_interrupt_kind kind = frv_interrupt_state.queue[j].kind; 12844e98e3e1Schristos struct frv_interrupt* interrupt = & frv_interrupt_table[kind]; 12854e98e3e1Schristos if (interrupt->iclass <= high_class) 12864e98e3e1Schristos break; 12874e98e3e1Schristos } 12884e98e3e1Schristos 12894e98e3e1Schristos /* Shuffle the remaining high priority interrupts down into the empty space 12904e98e3e1Schristos left by the deleted interrupts. */ 12914e98e3e1Schristos if (j >= i) 12924e98e3e1Schristos { 12934e98e3e1Schristos for (++j; j < limit; ++j) 12944e98e3e1Schristos frv_interrupt_state.queue[i++] = frv_interrupt_state.queue[j]; 12954e98e3e1Schristos frv_interrupt_state.queue_index -= (j - i); 12964e98e3e1Schristos } 12974e98e3e1Schristos } 12984e98e3e1Schristos 12994e98e3e1Schristos /* Save data written to memory into the interrupt state so that it can be 13004e98e3e1Schristos copied to the appropriate EDR register, if necessary, in the event of an 13014e98e3e1Schristos interrupt. */ 13024e98e3e1Schristos void 13034e98e3e1Schristos frv_save_data_written_for_interrupts ( 13044e98e3e1Schristos SIM_CPU *current_cpu, CGEN_WRITE_QUEUE_ELEMENT *item 13054e98e3e1Schristos ) 13064e98e3e1Schristos { 13074e98e3e1Schristos /* Record the slot containing the insn doing the write in the 13084e98e3e1Schristos interrupt state. */ 13094e98e3e1Schristos frv_interrupt_state.slot = CGEN_WRITE_QUEUE_ELEMENT_PIPE (item); 13104e98e3e1Schristos 13114e98e3e1Schristos /* Now record any data written to memory in the interrupt state. */ 13124e98e3e1Schristos switch (CGEN_WRITE_QUEUE_ELEMENT_KIND (item)) 13134e98e3e1Schristos { 13144e98e3e1Schristos case CGEN_BI_WRITE: 13154e98e3e1Schristos case CGEN_QI_WRITE: 13164e98e3e1Schristos case CGEN_SI_WRITE: 13174e98e3e1Schristos case CGEN_SF_WRITE: 13184e98e3e1Schristos case CGEN_PC_WRITE: 13194e98e3e1Schristos case CGEN_FN_HI_WRITE: 13204e98e3e1Schristos case CGEN_FN_SI_WRITE: 13214e98e3e1Schristos case CGEN_FN_SF_WRITE: 13224e98e3e1Schristos case CGEN_FN_DI_WRITE: 13234e98e3e1Schristos case CGEN_FN_DF_WRITE: 13244e98e3e1Schristos case CGEN_FN_XI_WRITE: 13254e98e3e1Schristos case CGEN_FN_PC_WRITE: 13264e98e3e1Schristos break; /* Ignore writes to registers. */ 13274e98e3e1Schristos case CGEN_MEM_QI_WRITE: 13284e98e3e1Schristos frv_interrupt_state.data_written.length = 1; 13294e98e3e1Schristos frv_interrupt_state.data_written.words[0] 13304e98e3e1Schristos = item->kinds.mem_qi_write.value; 13314e98e3e1Schristos break; 13324e98e3e1Schristos case CGEN_MEM_HI_WRITE: 13334e98e3e1Schristos frv_interrupt_state.data_written.length = 1; 13344e98e3e1Schristos frv_interrupt_state.data_written.words[0] 13354e98e3e1Schristos = item->kinds.mem_hi_write.value; 13364e98e3e1Schristos break; 13374e98e3e1Schristos case CGEN_MEM_SI_WRITE: 13384e98e3e1Schristos frv_interrupt_state.data_written.length = 1; 13394e98e3e1Schristos frv_interrupt_state.data_written.words[0] 13404e98e3e1Schristos = item->kinds.mem_si_write.value; 13414e98e3e1Schristos break; 13424e98e3e1Schristos case CGEN_MEM_DI_WRITE: 13434e98e3e1Schristos frv_interrupt_state.data_written.length = 2; 13444e98e3e1Schristos frv_interrupt_state.data_written.words[0] 13454e98e3e1Schristos = item->kinds.mem_di_write.value >> 32; 13464e98e3e1Schristos frv_interrupt_state.data_written.words[1] 13474e98e3e1Schristos = item->kinds.mem_di_write.value; 13484e98e3e1Schristos break; 13494e98e3e1Schristos case CGEN_MEM_DF_WRITE: 13504e98e3e1Schristos frv_interrupt_state.data_written.length = 2; 13514e98e3e1Schristos frv_interrupt_state.data_written.words[0] 13524e98e3e1Schristos = item->kinds.mem_df_write.value >> 32; 13534e98e3e1Schristos frv_interrupt_state.data_written.words[1] 13544e98e3e1Schristos = item->kinds.mem_df_write.value; 13554e98e3e1Schristos break; 13564e98e3e1Schristos case CGEN_MEM_XI_WRITE: 13574e98e3e1Schristos frv_interrupt_state.data_written.length = 4; 13584e98e3e1Schristos frv_interrupt_state.data_written.words[0] 13594e98e3e1Schristos = item->kinds.mem_xi_write.value[0]; 13604e98e3e1Schristos frv_interrupt_state.data_written.words[1] 13614e98e3e1Schristos = item->kinds.mem_xi_write.value[1]; 13624e98e3e1Schristos frv_interrupt_state.data_written.words[2] 13634e98e3e1Schristos = item->kinds.mem_xi_write.value[2]; 13644e98e3e1Schristos frv_interrupt_state.data_written.words[3] 13654e98e3e1Schristos = item->kinds.mem_xi_write.value[3]; 13664e98e3e1Schristos break; 13674e98e3e1Schristos case CGEN_FN_MEM_QI_WRITE: 13684e98e3e1Schristos frv_interrupt_state.data_written.length = 1; 13694e98e3e1Schristos frv_interrupt_state.data_written.words[0] 13704e98e3e1Schristos = item->kinds.fn_mem_qi_write.value; 13714e98e3e1Schristos break; 13724e98e3e1Schristos case CGEN_FN_MEM_HI_WRITE: 13734e98e3e1Schristos frv_interrupt_state.data_written.length = 1; 13744e98e3e1Schristos frv_interrupt_state.data_written.words[0] 13754e98e3e1Schristos = item->kinds.fn_mem_hi_write.value; 13764e98e3e1Schristos break; 13774e98e3e1Schristos case CGEN_FN_MEM_SI_WRITE: 13784e98e3e1Schristos frv_interrupt_state.data_written.length = 1; 13794e98e3e1Schristos frv_interrupt_state.data_written.words[0] 13804e98e3e1Schristos = item->kinds.fn_mem_si_write.value; 13814e98e3e1Schristos break; 13824e98e3e1Schristos case CGEN_FN_MEM_DI_WRITE: 13834e98e3e1Schristos frv_interrupt_state.data_written.length = 2; 13844e98e3e1Schristos frv_interrupt_state.data_written.words[0] 13854e98e3e1Schristos = item->kinds.fn_mem_di_write.value >> 32; 13864e98e3e1Schristos frv_interrupt_state.data_written.words[1] 13874e98e3e1Schristos = item->kinds.fn_mem_di_write.value; 13884e98e3e1Schristos break; 13894e98e3e1Schristos case CGEN_FN_MEM_DF_WRITE: 13904e98e3e1Schristos frv_interrupt_state.data_written.length = 2; 13914e98e3e1Schristos frv_interrupt_state.data_written.words[0] 13924e98e3e1Schristos = item->kinds.fn_mem_df_write.value >> 32; 13934e98e3e1Schristos frv_interrupt_state.data_written.words[1] 13944e98e3e1Schristos = item->kinds.fn_mem_df_write.value; 13954e98e3e1Schristos break; 13964e98e3e1Schristos case CGEN_FN_MEM_XI_WRITE: 13974e98e3e1Schristos frv_interrupt_state.data_written.length = 4; 13984e98e3e1Schristos frv_interrupt_state.data_written.words[0] 13994e98e3e1Schristos = item->kinds.fn_mem_xi_write.value[0]; 14004e98e3e1Schristos frv_interrupt_state.data_written.words[1] 14014e98e3e1Schristos = item->kinds.fn_mem_xi_write.value[1]; 14024e98e3e1Schristos frv_interrupt_state.data_written.words[2] 14034e98e3e1Schristos = item->kinds.fn_mem_xi_write.value[2]; 14044e98e3e1Schristos frv_interrupt_state.data_written.words[3] 14054e98e3e1Schristos = item->kinds.fn_mem_xi_write.value[3]; 14064e98e3e1Schristos break; 14074e98e3e1Schristos default: 14084e98e3e1Schristos { 14094e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 14104e98e3e1Schristos IADDR pc = CPU_PC_GET (current_cpu); 14114e98e3e1Schristos sim_engine_abort (sd, current_cpu, pc, 14124e98e3e1Schristos "unknown write kind during save for interrupt\n"); 14134e98e3e1Schristos } 14144e98e3e1Schristos break; 14154e98e3e1Schristos } 14164e98e3e1Schristos } 1417