1 1.1 christos /* frv exception and interrupt support 2 1.1.1.10 christos Copyright (C) 1999-2024 Free Software Foundation, Inc. 3 1.1 christos Contributed by Red Hat. 4 1.1 christos 5 1.1 christos This file is part of the GNU simulators. 6 1.1 christos 7 1.1 christos This program is free software; you can redistribute it and/or modify 8 1.1 christos it under the terms of the GNU General Public License as published by 9 1.1 christos the Free Software Foundation; either version 3 of the License, or 10 1.1 christos (at your option) any later version. 11 1.1 christos 12 1.1 christos This program is distributed in the hope that it will be useful, 13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 1.1 christos GNU General Public License for more details. 16 1.1 christos 17 1.1 christos You should have received a copy of the GNU General Public License 18 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 1.1 christos 20 1.1.1.9 christos /* This must come before any other includes. */ 21 1.1.1.9 christos #include "defs.h" 22 1.1.1.9 christos 23 1.1 christos #define WANT_CPU frvbf 24 1.1 christos #define WANT_CPU_FRVBF 25 1.1 christos 26 1.1 christos #include "sim-main.h" 27 1.1.1.9 christos #include "sim-signal.h" 28 1.1 christos #include "bfd.h" 29 1.1.1.9 christos #include <stdlib.h> 30 1.1.1.9 christos #include "cgen-mem.h" 31 1.1 christos 32 1.1 christos /* FR-V Interrupt table. 33 1.1 christos Describes the interrupts supported by the FR-V. 34 1.1 christos This table *must* be maintained in order of interrupt priority as defined by 35 1.1 christos frv_interrupt_kind. */ 36 1.1 christos #define DEFERRED 1 37 1.1 christos #define PRECISE 1 38 1.1 christos #define ITABLE_ENTRY(name, class, deferral, precision, offset) \ 39 1.1 christos {FRV_##name, FRV_EC_##name, class, deferral, precision, offset} 40 1.1 christos 41 1.1 christos struct frv_interrupt frv_interrupt_table[NUM_FRV_INTERRUPT_KINDS] = 42 1.1 christos { 43 1.1 christos /* External interrupts */ 44 1.1 christos ITABLE_ENTRY(INTERRUPT_LEVEL_1, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x21), 45 1.1 christos ITABLE_ENTRY(INTERRUPT_LEVEL_2, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x22), 46 1.1 christos ITABLE_ENTRY(INTERRUPT_LEVEL_3, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x23), 47 1.1 christos ITABLE_ENTRY(INTERRUPT_LEVEL_4, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x24), 48 1.1 christos ITABLE_ENTRY(INTERRUPT_LEVEL_5, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x25), 49 1.1 christos ITABLE_ENTRY(INTERRUPT_LEVEL_6, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x26), 50 1.1 christos ITABLE_ENTRY(INTERRUPT_LEVEL_7, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x27), 51 1.1 christos ITABLE_ENTRY(INTERRUPT_LEVEL_8, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x28), 52 1.1 christos ITABLE_ENTRY(INTERRUPT_LEVEL_9, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x29), 53 1.1 christos ITABLE_ENTRY(INTERRUPT_LEVEL_10, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2a), 54 1.1 christos ITABLE_ENTRY(INTERRUPT_LEVEL_11, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2b), 55 1.1 christos ITABLE_ENTRY(INTERRUPT_LEVEL_12, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2c), 56 1.1 christos ITABLE_ENTRY(INTERRUPT_LEVEL_13, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2d), 57 1.1 christos ITABLE_ENTRY(INTERRUPT_LEVEL_14, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2e), 58 1.1 christos ITABLE_ENTRY(INTERRUPT_LEVEL_15, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2f), 59 1.1 christos /* Software interrupt */ 60 1.1 christos ITABLE_ENTRY(TRAP_INSTRUCTION, FRV_SOFTWARE_INTERRUPT, !DEFERRED, !PRECISE, 0x80), 61 1.1 christos /* Program interrupts */ 62 1.1 christos ITABLE_ENTRY(COMMIT_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x19), 63 1.1 christos ITABLE_ENTRY(DIVISION_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x17), 64 1.1 christos ITABLE_ENTRY(DATA_STORE_ERROR, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x14), 65 1.1 christos ITABLE_ENTRY(DATA_ACCESS_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x13), 66 1.1 christos ITABLE_ENTRY(DATA_ACCESS_MMU_MISS, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x12), 67 1.1 christos ITABLE_ENTRY(DATA_ACCESS_ERROR, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x11), 68 1.1 christos ITABLE_ENTRY(MP_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x0e), 69 1.1 christos ITABLE_ENTRY(FP_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x0d), 70 1.1 christos ITABLE_ENTRY(MEM_ADDRESS_NOT_ALIGNED, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x10), 71 1.1 christos ITABLE_ENTRY(REGISTER_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x08), 72 1.1 christos ITABLE_ENTRY(MP_DISABLED, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x0b), 73 1.1 christos ITABLE_ENTRY(FP_DISABLED, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x0a), 74 1.1 christos ITABLE_ENTRY(PRIVILEGED_INSTRUCTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x06), 75 1.1 christos ITABLE_ENTRY(ILLEGAL_INSTRUCTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x07), 76 1.1 christos ITABLE_ENTRY(INSTRUCTION_ACCESS_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x03), 77 1.1 christos ITABLE_ENTRY(INSTRUCTION_ACCESS_ERROR, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x02), 78 1.1 christos ITABLE_ENTRY(INSTRUCTION_ACCESS_MMU_MISS, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x01), 79 1.1 christos ITABLE_ENTRY(COMPOUND_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x20), 80 1.1 christos /* Break interrupt */ 81 1.1 christos ITABLE_ENTRY(BREAK_EXCEPTION, FRV_BREAK_INTERRUPT, !DEFERRED, !PRECISE, 0xff), 82 1.1 christos /* Reset interrupt */ 83 1.1 christos ITABLE_ENTRY(RESET, FRV_RESET_INTERRUPT, !DEFERRED, !PRECISE, 0x00) 84 1.1 christos }; 85 1.1 christos 86 1.1 christos /* The current interrupt state. */ 87 1.1 christos struct frv_interrupt_state frv_interrupt_state; 88 1.1 christos 89 1.1 christos /* maintain the address of the start of the previous VLIW insn sequence. */ 90 1.1 christos IADDR previous_vliw_pc; 91 1.1 christos 92 1.1 christos /* Add a break interrupt to the interrupt queue. */ 93 1.1 christos struct frv_interrupt_queue_element * 94 1.1 christos frv_queue_break_interrupt (SIM_CPU *current_cpu) 95 1.1 christos { 96 1.1 christos return frv_queue_interrupt (current_cpu, FRV_BREAK_EXCEPTION); 97 1.1 christos } 98 1.1 christos 99 1.1 christos /* Add a software interrupt to the interrupt queue. */ 100 1.1 christos struct frv_interrupt_queue_element * 101 1.1 christos frv_queue_software_interrupt (SIM_CPU *current_cpu, SI offset) 102 1.1 christos { 103 1.1 christos struct frv_interrupt_queue_element *new_element 104 1.1 christos = frv_queue_interrupt (current_cpu, FRV_TRAP_INSTRUCTION); 105 1.1 christos 106 1.1 christos struct frv_interrupt *interrupt = & frv_interrupt_table[new_element->kind]; 107 1.1 christos interrupt->handler_offset = offset; 108 1.1 christos 109 1.1 christos return new_element; 110 1.1 christos } 111 1.1 christos 112 1.1 christos /* Add a program interrupt to the interrupt queue. */ 113 1.1 christos struct frv_interrupt_queue_element * 114 1.1 christos frv_queue_program_interrupt ( 115 1.1 christos SIM_CPU *current_cpu, enum frv_interrupt_kind kind 116 1.1 christos ) 117 1.1 christos { 118 1.1 christos return frv_queue_interrupt (current_cpu, kind); 119 1.1 christos } 120 1.1 christos 121 1.1 christos /* Add an external interrupt to the interrupt queue. */ 122 1.1 christos struct frv_interrupt_queue_element * 123 1.1 christos frv_queue_external_interrupt ( 124 1.1 christos SIM_CPU *current_cpu, enum frv_interrupt_kind kind 125 1.1 christos ) 126 1.1 christos { 127 1.1 christos if (! GET_H_PSR_ET () 128 1.1 christos || (kind != FRV_INTERRUPT_LEVEL_15 && kind < GET_H_PSR_PIL ())) 129 1.1 christos return NULL; /* Leave it for later. */ 130 1.1 christos 131 1.1 christos return frv_queue_interrupt (current_cpu, kind); 132 1.1 christos } 133 1.1 christos 134 1.1 christos /* Add any interrupt to the interrupt queue. It will be added in reverse 135 1.1 christos priority order. This makes it easy to find the highest priority interrupt 136 1.1 christos at the end of the queue and to remove it after processing. */ 137 1.1 christos struct frv_interrupt_queue_element * 138 1.1 christos frv_queue_interrupt (SIM_CPU *current_cpu, enum frv_interrupt_kind kind) 139 1.1 christos { 140 1.1 christos int i; 141 1.1 christos int j; 142 1.1 christos int limit = frv_interrupt_state.queue_index; 143 1.1 christos struct frv_interrupt_queue_element *new_element; 144 1.1 christos enum frv_interrupt_class iclass; 145 1.1 christos 146 1.1 christos if (limit >= FRV_INTERRUPT_QUEUE_SIZE) 147 1.1 christos abort (); /* TODO: Make the queue dynamic */ 148 1.1 christos 149 1.1 christos /* Find the right place in the queue. */ 150 1.1 christos for (i = 0; i < limit; ++i) 151 1.1 christos { 152 1.1 christos if (frv_interrupt_state.queue[i].kind >= kind) 153 1.1 christos break; 154 1.1 christos } 155 1.1 christos 156 1.1 christos /* Don't queue two external interrupts of the same priority. */ 157 1.1 christos iclass = frv_interrupt_table[kind].iclass; 158 1.1 christos if (i < limit && iclass == FRV_EXTERNAL_INTERRUPT) 159 1.1 christos { 160 1.1 christos if (frv_interrupt_state.queue[i].kind == kind) 161 1.1 christos return & frv_interrupt_state.queue[i]; 162 1.1 christos } 163 1.1 christos 164 1.1 christos /* Make room for the new interrupt in this spot. */ 165 1.1 christos for (j = limit - 1; j >= i; --j) 166 1.1 christos frv_interrupt_state.queue[j + 1] = frv_interrupt_state.queue[j]; 167 1.1 christos 168 1.1 christos /* Add the new interrupt. */ 169 1.1 christos frv_interrupt_state.queue_index++; 170 1.1 christos new_element = & frv_interrupt_state.queue[i]; 171 1.1 christos new_element->kind = kind; 172 1.1 christos new_element->vpc = CPU_PC_GET (current_cpu); 173 1.1 christos new_element->u.data_written.length = 0; 174 1.1 christos frv_set_interrupt_queue_slot (current_cpu, new_element); 175 1.1 christos 176 1.1 christos return new_element; 177 1.1 christos } 178 1.1 christos 179 1.1 christos struct frv_interrupt_queue_element * 180 1.1 christos frv_queue_register_exception_interrupt (SIM_CPU *current_cpu, enum frv_rec rec) 181 1.1 christos { 182 1.1 christos struct frv_interrupt_queue_element *new_element = 183 1.1 christos frv_queue_program_interrupt (current_cpu, FRV_REGISTER_EXCEPTION); 184 1.1 christos 185 1.1 christos new_element->u.rec = rec; 186 1.1 christos 187 1.1 christos return new_element; 188 1.1 christos } 189 1.1 christos 190 1.1 christos struct frv_interrupt_queue_element * 191 1.1 christos frv_queue_mem_address_not_aligned_interrupt (SIM_CPU *current_cpu, USI addr) 192 1.1 christos { 193 1.1 christos struct frv_interrupt_queue_element *new_element; 194 1.1 christos USI isr = GET_ISR (); 195 1.1 christos 196 1.1 christos /* Make sure that this exception is not masked. */ 197 1.1 christos if (GET_ISR_EMAM (isr)) 198 1.1 christos return NULL; 199 1.1 christos 200 1.1 christos /* Queue the interrupt. */ 201 1.1 christos new_element = frv_queue_program_interrupt (current_cpu, 202 1.1 christos FRV_MEM_ADDRESS_NOT_ALIGNED); 203 1.1 christos new_element->eaddress = addr; 204 1.1 christos new_element->u.data_written = frv_interrupt_state.data_written; 205 1.1 christos frv_interrupt_state.data_written.length = 0; 206 1.1 christos 207 1.1 christos return new_element; 208 1.1 christos } 209 1.1 christos 210 1.1 christos struct frv_interrupt_queue_element * 211 1.1 christos frv_queue_data_access_error_interrupt (SIM_CPU *current_cpu, USI addr) 212 1.1 christos { 213 1.1 christos struct frv_interrupt_queue_element *new_element; 214 1.1 christos new_element = frv_queue_program_interrupt (current_cpu, 215 1.1 christos FRV_DATA_ACCESS_ERROR); 216 1.1 christos new_element->eaddress = addr; 217 1.1 christos return new_element; 218 1.1 christos } 219 1.1 christos 220 1.1 christos struct frv_interrupt_queue_element * 221 1.1 christos frv_queue_data_access_exception_interrupt (SIM_CPU *current_cpu) 222 1.1 christos { 223 1.1 christos return frv_queue_program_interrupt (current_cpu, FRV_DATA_ACCESS_EXCEPTION); 224 1.1 christos } 225 1.1 christos 226 1.1 christos struct frv_interrupt_queue_element * 227 1.1 christos frv_queue_instruction_access_error_interrupt (SIM_CPU *current_cpu) 228 1.1 christos { 229 1.1 christos return frv_queue_program_interrupt (current_cpu, FRV_INSTRUCTION_ACCESS_ERROR); 230 1.1 christos } 231 1.1 christos 232 1.1 christos struct frv_interrupt_queue_element * 233 1.1 christos frv_queue_instruction_access_exception_interrupt (SIM_CPU *current_cpu) 234 1.1 christos { 235 1.1 christos return frv_queue_program_interrupt (current_cpu, FRV_INSTRUCTION_ACCESS_EXCEPTION); 236 1.1 christos } 237 1.1 christos 238 1.1 christos struct frv_interrupt_queue_element * 239 1.1 christos frv_queue_illegal_instruction_interrupt ( 240 1.1 christos SIM_CPU *current_cpu, const CGEN_INSN *insn 241 1.1 christos ) 242 1.1 christos { 243 1.1 christos SIM_DESC sd = CPU_STATE (current_cpu); 244 1.1 christos switch (STATE_ARCHITECTURE (sd)->mach) 245 1.1 christos { 246 1.1 christos case bfd_mach_fr400: 247 1.1 christos case bfd_mach_fr450: 248 1.1 christos case bfd_mach_fr550: 249 1.1 christos break; 250 1.1 christos default: 251 1.1 christos /* Some machines generate fp_exception for this case. */ 252 1.1 christos if (frv_is_float_insn (insn) || frv_is_media_insn (insn)) 253 1.1 christos { 254 1.1 christos struct frv_fp_exception_info fp_info = { 255 1.1 christos FSR_NO_EXCEPTION, FTT_SEQUENCE_ERROR 256 1.1 christos }; 257 1.1 christos return frv_queue_fp_exception_interrupt (current_cpu, & fp_info); 258 1.1 christos } 259 1.1 christos break; 260 1.1 christos } 261 1.1 christos 262 1.1 christos return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); 263 1.1 christos } 264 1.1 christos 265 1.1 christos struct frv_interrupt_queue_element * 266 1.1 christos frv_queue_privileged_instruction_interrupt (SIM_CPU *current_cpu, const CGEN_INSN *insn) 267 1.1 christos { 268 1.1 christos /* The fr550 has no privileged instruction interrupt. It uses 269 1.1 christos illegal_instruction. */ 270 1.1 christos SIM_DESC sd = CPU_STATE (current_cpu); 271 1.1 christos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 272 1.1 christos return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); 273 1.1 christos 274 1.1 christos return frv_queue_program_interrupt (current_cpu, FRV_PRIVILEGED_INSTRUCTION); 275 1.1 christos } 276 1.1 christos 277 1.1 christos struct frv_interrupt_queue_element * 278 1.1 christos frv_queue_float_disabled_interrupt (SIM_CPU *current_cpu) 279 1.1 christos { 280 1.1 christos /* The fr550 has no fp_disabled interrupt. It uses illegal_instruction. */ 281 1.1 christos SIM_DESC sd = CPU_STATE (current_cpu); 282 1.1 christos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 283 1.1 christos return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); 284 1.1 christos 285 1.1 christos return frv_queue_program_interrupt (current_cpu, FRV_FP_DISABLED); 286 1.1 christos } 287 1.1 christos 288 1.1 christos struct frv_interrupt_queue_element * 289 1.1 christos frv_queue_media_disabled_interrupt (SIM_CPU *current_cpu) 290 1.1 christos { 291 1.1 christos /* The fr550 has no mp_disabled interrupt. It uses illegal_instruction. */ 292 1.1 christos SIM_DESC sd = CPU_STATE (current_cpu); 293 1.1 christos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 294 1.1 christos return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); 295 1.1 christos 296 1.1 christos return frv_queue_program_interrupt (current_cpu, FRV_MP_DISABLED); 297 1.1 christos } 298 1.1 christos 299 1.1 christos struct frv_interrupt_queue_element * 300 1.1 christos frv_queue_non_implemented_instruction_interrupt ( 301 1.1 christos SIM_CPU *current_cpu, const CGEN_INSN *insn 302 1.1 christos ) 303 1.1 christos { 304 1.1 christos SIM_DESC sd = CPU_STATE (current_cpu); 305 1.1 christos switch (STATE_ARCHITECTURE (sd)->mach) 306 1.1 christos { 307 1.1 christos case bfd_mach_fr400: 308 1.1 christos case bfd_mach_fr450: 309 1.1 christos case bfd_mach_fr550: 310 1.1 christos break; 311 1.1 christos default: 312 1.1 christos /* Some machines generate fp_exception or mp_exception for this case. */ 313 1.1 christos if (frv_is_float_insn (insn)) 314 1.1 christos { 315 1.1 christos struct frv_fp_exception_info fp_info = { 316 1.1 christos FSR_NO_EXCEPTION, FTT_UNIMPLEMENTED_FPOP 317 1.1 christos }; 318 1.1 christos return frv_queue_fp_exception_interrupt (current_cpu, & fp_info); 319 1.1 christos } 320 1.1 christos if (frv_is_media_insn (insn)) 321 1.1 christos { 322 1.1 christos frv_set_mp_exception_registers (current_cpu, MTT_UNIMPLEMENTED_MPOP, 323 1.1 christos 0); 324 1.1 christos return NULL; /* no interrupt queued at this time. */ 325 1.1 christos } 326 1.1 christos break; 327 1.1 christos } 328 1.1 christos 329 1.1 christos return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); 330 1.1 christos } 331 1.1 christos 332 1.1 christos /* Queue the given fp_exception interrupt. Also update fp_info by removing 333 1.1 christos masked interrupts and updating the 'slot' flield. */ 334 1.1 christos struct frv_interrupt_queue_element * 335 1.1 christos frv_queue_fp_exception_interrupt ( 336 1.1 christos SIM_CPU *current_cpu, struct frv_fp_exception_info *fp_info 337 1.1 christos ) 338 1.1 christos { 339 1.1 christos SI fsr0 = GET_FSR (0); 340 1.1 christos int tem = GET_FSR_TEM (fsr0); 341 1.1 christos int aexc = GET_FSR_AEXC (fsr0); 342 1.1 christos struct frv_interrupt_queue_element *new_element = NULL; 343 1.1 christos 344 1.1 christos /* Update AEXC with the interrupts that are masked. */ 345 1.1 christos aexc |= fp_info->fsr_mask & ~tem; 346 1.1 christos SET_FSR_AEXC (fsr0, aexc); 347 1.1 christos SET_FSR (0, fsr0); 348 1.1 christos 349 1.1 christos /* update fsr_mask with the exceptions that are enabled. */ 350 1.1 christos fp_info->fsr_mask &= tem; 351 1.1 christos 352 1.1 christos /* If there is an unmasked interrupt then queue it, unless 353 1.1 christos this was a non-excepting insn, in which case simply set the NE 354 1.1 christos status registers. */ 355 1.1 christos if (frv_interrupt_state.ne_index != NE_NOFLAG 356 1.1 christos && fp_info->fsr_mask != FSR_NO_EXCEPTION) 357 1.1 christos { 358 1.1 christos SET_NE_FLAG (frv_interrupt_state.f_ne_flags, 359 1.1 christos frv_interrupt_state.ne_index); 360 1.1 christos /* TODO -- Set NESR for chips which support it. */ 361 1.1 christos new_element = NULL; 362 1.1 christos } 363 1.1 christos else if (fp_info->fsr_mask != FSR_NO_EXCEPTION 364 1.1 christos || fp_info->ftt == FTT_UNIMPLEMENTED_FPOP 365 1.1 christos || fp_info->ftt == FTT_SEQUENCE_ERROR 366 1.1 christos || fp_info->ftt == FTT_INVALID_FR) 367 1.1 christos { 368 1.1 christos new_element = frv_queue_program_interrupt (current_cpu, FRV_FP_EXCEPTION); 369 1.1 christos new_element->u.fp_info = *fp_info; 370 1.1 christos } 371 1.1 christos 372 1.1 christos return new_element; 373 1.1 christos } 374 1.1 christos 375 1.1 christos struct frv_interrupt_queue_element * 376 1.1 christos frv_queue_division_exception_interrupt (SIM_CPU *current_cpu, enum frv_dtt dtt) 377 1.1 christos { 378 1.1 christos struct frv_interrupt_queue_element *new_element = 379 1.1 christos frv_queue_program_interrupt (current_cpu, FRV_DIVISION_EXCEPTION); 380 1.1 christos 381 1.1 christos new_element->u.dtt = dtt; 382 1.1 christos 383 1.1 christos return new_element; 384 1.1 christos } 385 1.1 christos 386 1.1 christos /* Check for interrupts caused by illegal insn access. These conditions are 387 1.1 christos checked in the order specified by the fr400 and fr500 LSI specs. */ 388 1.1 christos void 389 1.1 christos frv_detect_insn_access_interrupts (SIM_CPU *current_cpu, SCACHE *sc) 390 1.1 christos { 391 1.1 christos 392 1.1 christos const CGEN_INSN *insn = sc->argbuf.idesc->idata; 393 1.1 christos FRV_VLIW *vliw = CPU_VLIW (current_cpu); 394 1.1 christos 395 1.1 christos /* Check for vliw constraints. */ 396 1.1 christos if (vliw->constraint_violation) 397 1.1 christos frv_queue_illegal_instruction_interrupt (current_cpu, insn); 398 1.1 christos /* Check for non-excepting insns. */ 399 1.1 christos else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_NON_EXCEPTING) 400 1.1 christos && ! GET_H_PSR_NEM ()) 401 1.1 christos frv_queue_non_implemented_instruction_interrupt (current_cpu, insn); 402 1.1 christos /* Check for conditional insns. */ 403 1.1 christos else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONDITIONAL) 404 1.1 christos && ! GET_H_PSR_CM ()) 405 1.1 christos frv_queue_non_implemented_instruction_interrupt (current_cpu, insn); 406 1.1 christos /* Make sure floating point support is enabled. */ 407 1.1 christos else if (! GET_H_PSR_EF ()) 408 1.1 christos { 409 1.1 christos /* Generate fp_disabled if it is a floating point insn or if PSR.EM is 410 1.1 christos off and the insns accesses a fp register. */ 411 1.1 christos if (frv_is_float_insn (insn) 412 1.1 christos || (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR_ACCESS) 413 1.1 christos && ! GET_H_PSR_EM ())) 414 1.1 christos frv_queue_float_disabled_interrupt (current_cpu); 415 1.1 christos } 416 1.1 christos /* Make sure media support is enabled. */ 417 1.1 christos else if (! GET_H_PSR_EM ()) 418 1.1 christos { 419 1.1 christos /* Generate mp_disabled if it is a media insn. */ 420 1.1 christos if (frv_is_media_insn (insn) || CGEN_INSN_NUM (insn) == FRV_INSN_MTRAP) 421 1.1 christos frv_queue_media_disabled_interrupt (current_cpu); 422 1.1 christos } 423 1.1 christos /* Check for privileged insns. */ 424 1.1 christos else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_PRIVILEGED) && 425 1.1 christos ! GET_H_PSR_S ()) 426 1.1 christos frv_queue_privileged_instruction_interrupt (current_cpu, insn); 427 1.1 christos #if 0 /* disable for now until we find out how FSR0.QNE gets reset. */ 428 1.1 christos else 429 1.1 christos { 430 1.1 christos /* Enter the halt state if FSR0.QNE is set and we are executing a 431 1.1 christos floating point insn, a media insn or an insn which access a FR 432 1.1 christos register. */ 433 1.1.1.10 christos SIM_DESC sd = CPU_STATE (current_cpu); 434 1.1 christos SI fsr0 = GET_FSR (0); 435 1.1 christos if (GET_FSR_QNE (fsr0) 436 1.1 christos && (frv_is_float_insn (insn) || frv_is_media_insn (insn) 437 1.1 christos || CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR_ACCESS))) 438 1.1 christos { 439 1.1 christos sim_engine_halt (sd, current_cpu, NULL, GET_H_PC (), sim_stopped, 440 1.1 christos SIM_SIGINT); 441 1.1 christos } 442 1.1 christos } 443 1.1 christos #endif 444 1.1 christos } 445 1.1 christos 446 1.1 christos /* Record the current VLIW slot in the given interrupt queue element. */ 447 1.1 christos void 448 1.1 christos frv_set_interrupt_queue_slot ( 449 1.1 christos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item 450 1.1 christos ) 451 1.1 christos { 452 1.1 christos FRV_VLIW *vliw = CPU_VLIW (current_cpu); 453 1.1 christos int slot = vliw->next_slot - 1; 454 1.1 christos item->slot = (*vliw->current_vliw)[slot]; 455 1.1 christos } 456 1.1 christos 457 1.1 christos /* Handle an individual interrupt. */ 458 1.1 christos static void 459 1.1 christos handle_interrupt (SIM_CPU *current_cpu, IADDR pc) 460 1.1 christos { 461 1.1 christos struct frv_interrupt *interrupt; 462 1.1 christos int writeback_done = 0; 463 1.1 christos while (1) 464 1.1 christos { 465 1.1 christos /* Interrupts are queued in priority order with the highest priority 466 1.1 christos last. */ 467 1.1 christos int index = frv_interrupt_state.queue_index - 1; 468 1.1 christos struct frv_interrupt_queue_element *item 469 1.1 christos = & frv_interrupt_state.queue[index]; 470 1.1 christos interrupt = & frv_interrupt_table[item->kind]; 471 1.1 christos 472 1.1 christos switch (interrupt->iclass) 473 1.1 christos { 474 1.1 christos case FRV_EXTERNAL_INTERRUPT: 475 1.1 christos /* Perform writeback first. This may cause a higher priority 476 1.1 christos interrupt. */ 477 1.1 christos if (! writeback_done) 478 1.1 christos { 479 1.1 christos frvbf_perform_writeback (current_cpu); 480 1.1 christos writeback_done = 1; 481 1.1 christos continue; 482 1.1 christos } 483 1.1 christos frv_external_interrupt (current_cpu, item, pc); 484 1.1 christos return; 485 1.1 christos case FRV_SOFTWARE_INTERRUPT: 486 1.1 christos frv_interrupt_state.queue_index = index; 487 1.1 christos frv_software_interrupt (current_cpu, item, pc); 488 1.1 christos return; 489 1.1 christos case FRV_PROGRAM_INTERRUPT: 490 1.1 christos /* If the program interrupt is not strict (imprecise), then perform 491 1.1 christos writeback first. This may, in turn, cause a higher priority 492 1.1 christos interrupt. */ 493 1.1 christos if (! interrupt->precise && ! writeback_done) 494 1.1 christos { 495 1.1 christos frv_interrupt_state.imprecise_interrupt = item; 496 1.1 christos frvbf_perform_writeback (current_cpu); 497 1.1 christos writeback_done = 1; 498 1.1 christos continue; 499 1.1 christos } 500 1.1 christos frv_interrupt_state.queue_index = index; 501 1.1 christos frv_program_interrupt (current_cpu, item, pc); 502 1.1 christos return; 503 1.1 christos case FRV_BREAK_INTERRUPT: 504 1.1 christos frv_interrupt_state.queue_index = index; 505 1.1 christos frv_break_interrupt (current_cpu, interrupt, pc); 506 1.1 christos return; 507 1.1 christos case FRV_RESET_INTERRUPT: 508 1.1 christos break; 509 1.1 christos default: 510 1.1 christos break; 511 1.1 christos } 512 1.1 christos frv_interrupt_state.queue_index = index; 513 1.1 christos break; /* out of loop. */ 514 1.1 christos } 515 1.1 christos 516 1.1 christos /* We should never get here. */ 517 1.1 christos { 518 1.1 christos SIM_DESC sd = CPU_STATE (current_cpu); 519 1.1 christos sim_engine_abort (sd, current_cpu, pc, 520 1.1 christos "interrupt class not supported %d\n", 521 1.1 christos interrupt->iclass); 522 1.1 christos } 523 1.1 christos } 524 1.1 christos 525 1.1 christos /* Check to see the if the RSTR.HR or RSTR.SR bits have been set. If so, handle 526 1.1 christos the appropriate reset interrupt. */ 527 1.1 christos static int 528 1.1 christos check_reset (SIM_CPU *current_cpu, IADDR pc) 529 1.1 christos { 530 1.1 christos int hsr0; 531 1.1 christos int hr; 532 1.1 christos int sr; 533 1.1 christos SI rstr; 534 1.1 christos FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu); 535 1.1 christos IADDR address = RSTR_ADDRESS; 536 1.1 christos 537 1.1 christos /* We don't want this to show up in the cache statistics, so read the 538 1.1 christos cache passively. */ 539 1.1 christos if (! frv_cache_read_passive_SI (cache, address, & rstr)) 540 1.1 christos rstr = sim_core_read_unaligned_4 (current_cpu, pc, read_map, address); 541 1.1 christos 542 1.1 christos hr = GET_RSTR_HR (rstr); 543 1.1 christos sr = GET_RSTR_SR (rstr); 544 1.1 christos 545 1.1 christos if (! hr && ! sr) 546 1.1 christos return 0; /* no reset. */ 547 1.1 christos 548 1.1 christos /* Reinitialize the machine state. */ 549 1.1 christos if (hr) 550 1.1 christos frv_hardware_reset (current_cpu); 551 1.1 christos else 552 1.1 christos frv_software_reset (current_cpu); 553 1.1 christos 554 1.1 christos /* Branch to the reset address. */ 555 1.1 christos hsr0 = GET_HSR0 (); 556 1.1 christos if (GET_HSR0_SA (hsr0)) 557 1.1 christos SET_H_PC (0xff000000); 558 1.1 christos else 559 1.1 christos SET_H_PC (0); 560 1.1 christos 561 1.1 christos return 1; /* reset */ 562 1.1 christos } 563 1.1 christos 564 1.1 christos /* Process any pending interrupt(s) after a group of parallel insns. */ 565 1.1 christos void 566 1.1 christos frv_process_interrupts (SIM_CPU *current_cpu) 567 1.1 christos { 568 1.1 christos SI NE_flags[2]; 569 1.1 christos /* Need to save the pc here because writeback may change it (due to a 570 1.1 christos branch). */ 571 1.1 christos IADDR pc = CPU_PC_GET (current_cpu); 572 1.1 christos 573 1.1 christos /* Check for a reset before anything else. */ 574 1.1 christos if (check_reset (current_cpu, pc)) 575 1.1 christos return; 576 1.1 christos 577 1.1 christos /* First queue the writes for any accumulated NE flags. */ 578 1.1 christos if (frv_interrupt_state.f_ne_flags[0] != 0 579 1.1 christos || frv_interrupt_state.f_ne_flags[1] != 0) 580 1.1 christos { 581 1.1 christos GET_NE_FLAGS (NE_flags, H_SPR_FNER0); 582 1.1 christos NE_flags[0] |= frv_interrupt_state.f_ne_flags[0]; 583 1.1 christos NE_flags[1] |= frv_interrupt_state.f_ne_flags[1]; 584 1.1 christos SET_NE_FLAGS (H_SPR_FNER0, NE_flags); 585 1.1 christos } 586 1.1 christos 587 1.1 christos /* If there is no interrupt pending, then perform parallel writeback. This 588 1.1 christos may cause an interrupt. */ 589 1.1 christos if (frv_interrupt_state.queue_index <= 0) 590 1.1 christos frvbf_perform_writeback (current_cpu); 591 1.1 christos 592 1.1 christos /* If there is an interrupt pending, then process it. */ 593 1.1 christos if (frv_interrupt_state.queue_index > 0) 594 1.1 christos handle_interrupt (current_cpu, pc); 595 1.1 christos } 596 1.1 christos 597 1.1 christos /* Find the next available ESR and return its index */ 598 1.1 christos static int 599 1.1 christos esr_for_data_access_exception ( 600 1.1 christos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item 601 1.1 christos ) 602 1.1 christos { 603 1.1 christos SIM_DESC sd = CPU_STATE (current_cpu); 604 1.1 christos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 605 1.1 christos return 8; /* Use ESR8, EPCR8. */ 606 1.1 christos 607 1.1 christos if (item->slot == UNIT_I0) 608 1.1 christos return 8; /* Use ESR8, EPCR8, EAR8, EDR8. */ 609 1.1 christos 610 1.1 christos return 9; /* Use ESR9, EPCR9, EAR9. */ 611 1.1 christos } 612 1.1 christos 613 1.1 christos /* Set the next available EDR register with the data which was to be stored 614 1.1 christos and return the index of the register. */ 615 1.1 christos static int 616 1.1 christos set_edr_register ( 617 1.1 christos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, int edr_index 618 1.1 christos ) 619 1.1 christos { 620 1.1 christos /* EDR0, EDR4 and EDR8 are available as blocks of 4. 621 1.1 christos SI data uses EDR3, EDR7 and EDR11 622 1.1 christos DI data uses EDR2, EDR6 and EDR10 623 1.1 christos XI data uses EDR0, EDR4 and EDR8. */ 624 1.1 christos int i; 625 1.1 christos edr_index += 4 - item->u.data_written.length; 626 1.1 christos for (i = 0; i < item->u.data_written.length; ++i) 627 1.1 christos SET_EDR (edr_index + i, item->u.data_written.words[i]); 628 1.1 christos 629 1.1 christos return edr_index; 630 1.1 christos }; 631 1.1 christos 632 1.1 christos /* Clear ESFR0, EPCRx, ESRx, EARx and EDRx. */ 633 1.1 christos static void 634 1.1 christos clear_exception_status_registers (SIM_CPU *current_cpu) 635 1.1 christos { 636 1.1 christos int i; 637 1.1 christos /* It is only necessary to clear the flag bits indicating which registers 638 1.1 christos are valid. */ 639 1.1 christos SET_ESFR (0, 0); 640 1.1 christos SET_ESFR (1, 0); 641 1.1 christos 642 1.1 christos for (i = 0; i <= 2; ++i) 643 1.1 christos { 644 1.1 christos SI esr = GET_ESR (i); 645 1.1 christos CLEAR_ESR_VALID (esr); 646 1.1 christos SET_ESR (i, esr); 647 1.1 christos } 648 1.1 christos for (i = 8; i <= 15; ++i) 649 1.1 christos { 650 1.1 christos SI esr = GET_ESR (i); 651 1.1 christos CLEAR_ESR_VALID (esr); 652 1.1 christos SET_ESR (i, esr); 653 1.1 christos } 654 1.1 christos } 655 1.1 christos 656 1.1 christos /* Record state for media exception. */ 657 1.1 christos void 658 1.1 christos frv_set_mp_exception_registers ( 659 1.1 christos SIM_CPU *current_cpu, enum frv_msr_mtt mtt, int sie 660 1.1 christos ) 661 1.1 christos { 662 1.1 christos /* Record the interrupt factor in MSR0. */ 663 1.1 christos SI msr0 = GET_MSR (0); 664 1.1 christos if (GET_MSR_MTT (msr0) == MTT_NONE) 665 1.1 christos SET_MSR_MTT (msr0, mtt); 666 1.1 christos 667 1.1 christos /* Also set the OVF bit in the appropriate MSR as well as MSR0.AOVF. */ 668 1.1 christos if (mtt == MTT_OVERFLOW) 669 1.1 christos { 670 1.1 christos FRV_VLIW *vliw = CPU_VLIW (current_cpu); 671 1.1 christos int slot = vliw->next_slot - 1; 672 1.1 christos SIM_DESC sd = CPU_STATE (current_cpu); 673 1.1 christos 674 1.1 christos /* If this insn is in the M2 slot, then set MSR1.OVF and MSR1.SIE, 675 1.1 christos otherwise set MSR0.OVF and MSR0.SIE. */ 676 1.1 christos if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550 && (*vliw->current_vliw)[slot] == UNIT_FM1) 677 1.1 christos { 678 1.1 christos SI msr = GET_MSR (1); 679 1.1 christos OR_MSR_SIE (msr, sie); 680 1.1 christos SET_MSR_OVF (msr); 681 1.1 christos SET_MSR (1, msr); 682 1.1 christos } 683 1.1 christos else 684 1.1 christos { 685 1.1 christos OR_MSR_SIE (msr0, sie); 686 1.1 christos SET_MSR_OVF (msr0); 687 1.1 christos } 688 1.1 christos 689 1.1 christos /* Generate the interrupt now if MSR0.MPEM is set on fr550 */ 690 1.1 christos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550 && GET_MSR_MPEM (msr0)) 691 1.1 christos frv_queue_program_interrupt (current_cpu, FRV_MP_EXCEPTION); 692 1.1 christos else 693 1.1 christos { 694 1.1 christos /* Regardless of the slot, set MSR0.AOVF. */ 695 1.1 christos SET_MSR_AOVF (msr0); 696 1.1 christos } 697 1.1 christos } 698 1.1 christos 699 1.1 christos SET_MSR (0, msr0); 700 1.1 christos } 701 1.1 christos 702 1.1 christos /* Determine the correct FQ register to use for the given exception. 703 1.1 christos Return -1 if a register is not available. */ 704 1.1 christos static int 705 1.1 christos fq_for_exception ( 706 1.1 christos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item 707 1.1 christos ) 708 1.1 christos { 709 1.1 christos SI fq; 710 1.1 christos struct frv_fp_exception_info *fp_info = & item->u.fp_info; 711 1.1 christos 712 1.1 christos /* For fp_exception overflow, underflow or inexact, use FQ0 or FQ1. */ 713 1.1 christos if (fp_info->ftt == FTT_IEEE_754_EXCEPTION 714 1.1 christos && (fp_info->fsr_mask & (FSR_OVERFLOW | FSR_UNDERFLOW | FSR_INEXACT))) 715 1.1 christos { 716 1.1 christos fq = GET_FQ (0); 717 1.1 christos if (! GET_FQ_VALID (fq)) 718 1.1 christos return 0; /* FQ0 is available. */ 719 1.1 christos fq = GET_FQ (1); 720 1.1 christos if (! GET_FQ_VALID (fq)) 721 1.1 christos return 1; /* FQ1 is available. */ 722 1.1 christos 723 1.1 christos /* No FQ register is available */ 724 1.1 christos { 725 1.1 christos SIM_DESC sd = CPU_STATE (current_cpu); 726 1.1 christos IADDR pc = CPU_PC_GET (current_cpu); 727 1.1 christos sim_engine_abort (sd, current_cpu, pc, "No FQ register available\n"); 728 1.1 christos } 729 1.1 christos return -1; 730 1.1 christos } 731 1.1 christos /* For other exceptions, use FQ2 if the insn was in slot F0/I0 and FQ3 732 1.1 christos otherwise. */ 733 1.1 christos if (item->slot == UNIT_FM0 || item->slot == UNIT_I0) 734 1.1 christos return 2; 735 1.1 christos 736 1.1 christos return 3; 737 1.1 christos } 738 1.1 christos 739 1.1 christos /* Set FSR0, FQ0-FQ9, depending on the interrupt. */ 740 1.1 christos static void 741 1.1 christos set_fp_exception_registers ( 742 1.1 christos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item 743 1.1 christos ) 744 1.1 christos { 745 1.1 christos int fq_index; 746 1.1 christos SI fq; 747 1.1 christos SI insn; 748 1.1 christos SI fsr0; 749 1.1 christos IADDR pc; 750 1.1 christos struct frv_fp_exception_info *fp_info; 751 1.1 christos SIM_DESC sd = CPU_STATE (current_cpu); 752 1.1 christos 753 1.1 christos /* No FQ registers on fr550 */ 754 1.1 christos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 755 1.1 christos { 756 1.1 christos /* Update the fsr. */ 757 1.1 christos fp_info = & item->u.fp_info; 758 1.1 christos fsr0 = GET_FSR (0); 759 1.1 christos SET_FSR_FTT (fsr0, fp_info->ftt); 760 1.1 christos SET_FSR (0, fsr0); 761 1.1 christos return; 762 1.1 christos } 763 1.1 christos 764 1.1 christos /* Select an FQ and update it with the exception information. */ 765 1.1 christos fq_index = fq_for_exception (current_cpu, item); 766 1.1 christos if (fq_index == -1) 767 1.1 christos return; 768 1.1 christos 769 1.1 christos fp_info = & item->u.fp_info; 770 1.1 christos fq = GET_FQ (fq_index); 771 1.1 christos SET_FQ_MIV (fq, MIV_FLOAT); 772 1.1 christos SET_FQ_SIE (fq, SIE_NIL); 773 1.1 christos SET_FQ_FTT (fq, fp_info->ftt); 774 1.1 christos SET_FQ_CEXC (fq, fp_info->fsr_mask); 775 1.1 christos SET_FQ_VALID (fq); 776 1.1 christos SET_FQ (fq_index, fq); 777 1.1 christos 778 1.1 christos /* Write the failing insn into FQx.OPC. */ 779 1.1 christos pc = item->vpc; 780 1.1 christos insn = GETMEMSI (current_cpu, pc, pc); 781 1.1 christos SET_FQ_OPC (fq_index, insn); 782 1.1 christos 783 1.1 christos /* Update the fsr. */ 784 1.1 christos fsr0 = GET_FSR (0); 785 1.1 christos SET_FSR_QNE (fsr0); /* FQ not empty */ 786 1.1 christos SET_FSR_FTT (fsr0, fp_info->ftt); 787 1.1 christos SET_FSR (0, fsr0); 788 1.1 christos } 789 1.1 christos 790 1.1 christos /* Record the state of a division exception in the ISR. */ 791 1.1 christos static void 792 1.1 christos set_isr_exception_fields ( 793 1.1 christos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item 794 1.1 christos ) 795 1.1 christos { 796 1.1 christos USI isr = GET_ISR (); 797 1.1 christos int dtt = GET_ISR_DTT (isr); 798 1.1 christos dtt |= item->u.dtt; 799 1.1 christos SET_ISR_DTT (isr, dtt); 800 1.1 christos SET_ISR (isr); 801 1.1 christos } 802 1.1 christos 803 1.1 christos /* Set ESFR0, EPCRx, ESRx, EARx and EDRx, according to the given program 804 1.1 christos interrupt. */ 805 1.1 christos static void 806 1.1 christos set_exception_status_registers ( 807 1.1 christos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item 808 1.1 christos ) 809 1.1 christos { 810 1.1 christos struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind]; 811 1.1 christos int reg_index = -1; 812 1.1 christos int set_ear = 0; 813 1.1 christos int set_edr = 0; 814 1.1 christos int set_daec = 0; 815 1.1 christos int set_epcr = 0; 816 1.1 christos SI esr = 0; 817 1.1 christos SIM_DESC sd = CPU_STATE (current_cpu); 818 1.1 christos 819 1.1 christos /* If the interrupt is strict (precise) or the interrupt is on the insns 820 1.1 christos in the I0 pipe, then set the 0 registers. */ 821 1.1 christos if (interrupt->precise) 822 1.1 christos { 823 1.1 christos reg_index = 0; 824 1.1 christos if (interrupt->kind == FRV_REGISTER_EXCEPTION) 825 1.1 christos SET_ESR_REC (esr, item->u.rec); 826 1.1 christos else if (interrupt->kind == FRV_INSTRUCTION_ACCESS_EXCEPTION) 827 1.1 christos SET_ESR_IAEC (esr, item->u.iaec); 828 1.1 christos /* For fr550, don't set epcr for precise interrupts. */ 829 1.1 christos if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550) 830 1.1 christos set_epcr = 1; 831 1.1 christos } 832 1.1 christos else 833 1.1 christos { 834 1.1 christos switch (interrupt->kind) 835 1.1 christos { 836 1.1 christos case FRV_DIVISION_EXCEPTION: 837 1.1 christos set_isr_exception_fields (current_cpu, item); 838 1.1.1.10 christos ATTRIBUTE_FALLTHROUGH; /* To set reg_index. */ 839 1.1 christos case FRV_COMMIT_EXCEPTION: 840 1.1 christos /* For fr550, always use ESR0. */ 841 1.1 christos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 842 1.1 christos reg_index = 0; 843 1.1 christos else if (item->slot == UNIT_I0) 844 1.1 christos reg_index = 0; 845 1.1 christos else if (item->slot == UNIT_I1) 846 1.1 christos reg_index = 1; 847 1.1 christos set_epcr = 1; 848 1.1 christos break; 849 1.1 christos case FRV_DATA_STORE_ERROR: 850 1.1 christos reg_index = 14; /* Use ESR14. */ 851 1.1 christos break; 852 1.1 christos case FRV_DATA_ACCESS_ERROR: 853 1.1 christos reg_index = 15; /* Use ESR15, EPCR15. */ 854 1.1 christos set_ear = 1; 855 1.1 christos break; 856 1.1 christos case FRV_DATA_ACCESS_EXCEPTION: 857 1.1 christos set_daec = 1; 858 1.1.1.10 christos ATTRIBUTE_FALLTHROUGH; 859 1.1 christos case FRV_DATA_ACCESS_MMU_MISS: 860 1.1 christos case FRV_MEM_ADDRESS_NOT_ALIGNED: 861 1.1 christos /* Get the appropriate ESR, EPCR, EAR and EDR. 862 1.1 christos EAR will be set. EDR will not be set if this is a store insn. */ 863 1.1 christos set_ear = 1; 864 1.1 christos /* For fr550, never use EDRx. */ 865 1.1 christos if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550) 866 1.1 christos if (item->u.data_written.length != 0) 867 1.1 christos set_edr = 1; 868 1.1 christos reg_index = esr_for_data_access_exception (current_cpu, item); 869 1.1 christos set_epcr = 1; 870 1.1 christos break; 871 1.1 christos case FRV_MP_EXCEPTION: 872 1.1 christos /* For fr550, use EPCR2 and ESR2. */ 873 1.1 christos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 874 1.1 christos { 875 1.1 christos reg_index = 2; 876 1.1 christos set_epcr = 1; 877 1.1 christos } 878 1.1 christos break; /* MSR0-1, FQ0-9 are already set. */ 879 1.1 christos case FRV_FP_EXCEPTION: 880 1.1 christos set_fp_exception_registers (current_cpu, item); 881 1.1 christos /* For fr550, use EPCR2 and ESR2. */ 882 1.1 christos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) 883 1.1 christos { 884 1.1 christos reg_index = 2; 885 1.1 christos set_epcr = 1; 886 1.1 christos } 887 1.1 christos break; 888 1.1 christos default: 889 1.1 christos { 890 1.1 christos IADDR pc = CPU_PC_GET (current_cpu); 891 1.1 christos sim_engine_abort (sd, current_cpu, pc, 892 1.1 christos "invalid non-strict program interrupt kind: %d\n", 893 1.1 christos interrupt->kind); 894 1.1 christos break; 895 1.1 christos } 896 1.1 christos } 897 1.1 christos } /* non-strict (imprecise) interrupt */ 898 1.1 christos 899 1.1 christos /* Now fill in the selected exception status registers. */ 900 1.1 christos if (reg_index != -1) 901 1.1 christos { 902 1.1 christos /* Now set the exception status registers. */ 903 1.1 christos SET_ESFR_FLAG (reg_index); 904 1.1 christos SET_ESR_EC (esr, interrupt->ec); 905 1.1 christos 906 1.1 christos if (set_epcr) 907 1.1 christos { 908 1.1 christos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400) 909 1.1 christos SET_EPCR (reg_index, previous_vliw_pc); 910 1.1 christos else 911 1.1 christos SET_EPCR (reg_index, item->vpc); 912 1.1 christos } 913 1.1 christos 914 1.1 christos if (set_ear) 915 1.1 christos { 916 1.1 christos SET_EAR (reg_index, item->eaddress); 917 1.1 christos SET_ESR_EAV (esr); 918 1.1 christos } 919 1.1 christos else 920 1.1 christos CLEAR_ESR_EAV (esr); 921 1.1 christos 922 1.1 christos if (set_edr) 923 1.1 christos { 924 1.1 christos int edn = set_edr_register (current_cpu, item, 0/* EDR0-3 */); 925 1.1 christos SET_ESR_EDN (esr, edn); 926 1.1 christos SET_ESR_EDV (esr); 927 1.1 christos } 928 1.1 christos else 929 1.1 christos CLEAR_ESR_EDV (esr); 930 1.1 christos 931 1.1 christos if (set_daec) 932 1.1 christos SET_ESR_DAEC (esr, item->u.daec); 933 1.1 christos 934 1.1 christos SET_ESR_VALID (esr); 935 1.1 christos SET_ESR (reg_index, esr); 936 1.1 christos } 937 1.1 christos } 938 1.1 christos 939 1.1 christos /* Check for compound interrupts. 940 1.1 christos Returns NULL if no interrupt is to be processed. */ 941 1.1 christos static struct frv_interrupt * 942 1.1 christos check_for_compound_interrupt ( 943 1.1 christos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item 944 1.1 christos ) 945 1.1 christos { 946 1.1 christos struct frv_interrupt *interrupt; 947 1.1 christos 948 1.1 christos /* Set the exception status registers for the original interrupt. */ 949 1.1 christos set_exception_status_registers (current_cpu, item); 950 1.1 christos interrupt = & frv_interrupt_table[item->kind]; 951 1.1 christos 952 1.1 christos if (! interrupt->precise) 953 1.1 christos { 954 1.1 christos IADDR vpc = 0; 955 1.1 christos int mask = 0; 956 1.1 christos 957 1.1 christos vpc = item->vpc; 958 1.1 christos mask = (1 << item->kind); 959 1.1 christos 960 1.1 christos /* Look for more queued program interrupts which are non-deferred 961 1.1 christos (pending inhibit), imprecise (non-strict) different than an interrupt 962 1.1 christos already found and caused by a different insn. A bit mask is used 963 1.1 christos to keep track of interrupts which have already been detected. */ 964 1.1 christos while (item != frv_interrupt_state.queue) 965 1.1 christos { 966 1.1 christos enum frv_interrupt_kind kind; 967 1.1 christos struct frv_interrupt *next_interrupt; 968 1.1 christos --item; 969 1.1 christos kind = item->kind; 970 1.1 christos next_interrupt = & frv_interrupt_table[kind]; 971 1.1 christos 972 1.1 christos if (next_interrupt->iclass != FRV_PROGRAM_INTERRUPT) 973 1.1 christos break; /* no program interrupts left. */ 974 1.1 christos 975 1.1 christos if (item->vpc == vpc) 976 1.1 christos continue; /* caused by the same insn. */ 977 1.1 christos 978 1.1 christos vpc = item->vpc; 979 1.1 christos if (! next_interrupt->precise && ! next_interrupt->deferred) 980 1.1 christos { 981 1.1 christos if (! (mask & (1 << kind))) 982 1.1 christos { 983 1.1 christos /* Set the exception status registers for the additional 984 1.1 christos interrupt. */ 985 1.1 christos set_exception_status_registers (current_cpu, item); 986 1.1 christos mask |= (1 << kind); 987 1.1 christos interrupt = & frv_interrupt_table[FRV_COMPOUND_EXCEPTION]; 988 1.1 christos } 989 1.1 christos } 990 1.1 christos } 991 1.1 christos } 992 1.1 christos 993 1.1 christos /* Return with either the original interrupt, a compound_exception, 994 1.1 christos or no exception. */ 995 1.1 christos return interrupt; 996 1.1 christos } 997 1.1 christos 998 1.1 christos /* Handle a program interrupt. */ 999 1.1 christos void 1000 1.1 christos frv_program_interrupt ( 1001 1.1 christos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc 1002 1.1 christos ) 1003 1.1 christos { 1004 1.1 christos struct frv_interrupt *interrupt; 1005 1.1 christos 1006 1.1 christos clear_exception_status_registers (current_cpu); 1007 1.1 christos /* If two or more non-deferred imprecise (non-strict) interrupts occur 1008 1.1 christos on two or more insns, then generate a compound_exception. */ 1009 1.1 christos interrupt = check_for_compound_interrupt (current_cpu, item); 1010 1.1 christos if (interrupt != NULL) 1011 1.1 christos { 1012 1.1 christos frv_program_or_software_interrupt (current_cpu, interrupt, pc); 1013 1.1 christos frv_clear_interrupt_classes (FRV_SOFTWARE_INTERRUPT, 1014 1.1 christos FRV_PROGRAM_INTERRUPT); 1015 1.1 christos } 1016 1.1 christos } 1017 1.1 christos 1018 1.1 christos /* Handle a software interrupt. */ 1019 1.1 christos void 1020 1.1 christos frv_software_interrupt ( 1021 1.1 christos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc 1022 1.1 christos ) 1023 1.1 christos { 1024 1.1 christos struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind]; 1025 1.1 christos frv_program_or_software_interrupt (current_cpu, interrupt, pc); 1026 1.1 christos } 1027 1.1 christos 1028 1.1 christos /* Handle a program interrupt or a software interrupt in non-operating mode. */ 1029 1.1 christos void 1030 1.1 christos frv_non_operating_interrupt ( 1031 1.1 christos SIM_CPU *current_cpu, enum frv_interrupt_kind kind, IADDR pc 1032 1.1 christos ) 1033 1.1 christos { 1034 1.1 christos SIM_DESC sd = CPU_STATE (current_cpu); 1035 1.1 christos switch (kind) 1036 1.1 christos { 1037 1.1 christos case FRV_INTERRUPT_LEVEL_1: 1038 1.1 christos case FRV_INTERRUPT_LEVEL_2: 1039 1.1 christos case FRV_INTERRUPT_LEVEL_3: 1040 1.1 christos case FRV_INTERRUPT_LEVEL_4: 1041 1.1 christos case FRV_INTERRUPT_LEVEL_5: 1042 1.1 christos case FRV_INTERRUPT_LEVEL_6: 1043 1.1 christos case FRV_INTERRUPT_LEVEL_7: 1044 1.1 christos case FRV_INTERRUPT_LEVEL_8: 1045 1.1 christos case FRV_INTERRUPT_LEVEL_9: 1046 1.1 christos case FRV_INTERRUPT_LEVEL_10: 1047 1.1 christos case FRV_INTERRUPT_LEVEL_11: 1048 1.1 christos case FRV_INTERRUPT_LEVEL_12: 1049 1.1 christos case FRV_INTERRUPT_LEVEL_13: 1050 1.1 christos case FRV_INTERRUPT_LEVEL_14: 1051 1.1 christos case FRV_INTERRUPT_LEVEL_15: 1052 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1053 1.1 christos "interrupt: external %d\n", kind + 1); 1054 1.1 christos break; 1055 1.1 christos case FRV_TRAP_INSTRUCTION: 1056 1.1 christos break; /* handle as in operating mode. */ 1057 1.1 christos case FRV_COMMIT_EXCEPTION: 1058 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1059 1.1 christos "interrupt: commit_exception\n"); 1060 1.1 christos break; 1061 1.1 christos case FRV_DIVISION_EXCEPTION: 1062 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1063 1.1 christos "interrupt: division_exception\n"); 1064 1.1 christos break; 1065 1.1 christos case FRV_DATA_STORE_ERROR: 1066 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1067 1.1 christos "interrupt: data_store_error\n"); 1068 1.1 christos break; 1069 1.1 christos case FRV_DATA_ACCESS_EXCEPTION: 1070 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1071 1.1 christos "interrupt: data_access_exception\n"); 1072 1.1 christos break; 1073 1.1 christos case FRV_DATA_ACCESS_MMU_MISS: 1074 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1075 1.1 christos "interrupt: data_access_mmu_miss\n"); 1076 1.1 christos break; 1077 1.1 christos case FRV_DATA_ACCESS_ERROR: 1078 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1079 1.1 christos "interrupt: data_access_error\n"); 1080 1.1 christos break; 1081 1.1 christos case FRV_MP_EXCEPTION: 1082 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1083 1.1 christos "interrupt: mp_exception\n"); 1084 1.1 christos break; 1085 1.1 christos case FRV_FP_EXCEPTION: 1086 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1087 1.1 christos "interrupt: fp_exception\n"); 1088 1.1 christos break; 1089 1.1 christos case FRV_MEM_ADDRESS_NOT_ALIGNED: 1090 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1091 1.1 christos "interrupt: mem_address_not_aligned\n"); 1092 1.1 christos break; 1093 1.1 christos case FRV_REGISTER_EXCEPTION: 1094 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1095 1.1 christos "interrupt: register_exception\n"); 1096 1.1 christos break; 1097 1.1 christos case FRV_MP_DISABLED: 1098 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1099 1.1 christos "interrupt: mp_disabled\n"); 1100 1.1 christos break; 1101 1.1 christos case FRV_FP_DISABLED: 1102 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1103 1.1 christos "interrupt: fp_disabled\n"); 1104 1.1 christos break; 1105 1.1 christos case FRV_PRIVILEGED_INSTRUCTION: 1106 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1107 1.1 christos "interrupt: privileged_instruction\n"); 1108 1.1 christos break; 1109 1.1 christos case FRV_ILLEGAL_INSTRUCTION: 1110 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1111 1.1 christos "interrupt: illegal_instruction\n"); 1112 1.1 christos break; 1113 1.1 christos case FRV_INSTRUCTION_ACCESS_EXCEPTION: 1114 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1115 1.1 christos "interrupt: instruction_access_exception\n"); 1116 1.1 christos break; 1117 1.1 christos case FRV_INSTRUCTION_ACCESS_MMU_MISS: 1118 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1119 1.1 christos "interrupt: instruction_access_mmu_miss\n"); 1120 1.1 christos break; 1121 1.1 christos case FRV_INSTRUCTION_ACCESS_ERROR: 1122 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1123 1.1 christos "interrupt: insn_access_error\n"); 1124 1.1 christos break; 1125 1.1 christos case FRV_COMPOUND_EXCEPTION: 1126 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1127 1.1 christos "interrupt: compound_exception\n"); 1128 1.1 christos break; 1129 1.1 christos case FRV_BREAK_EXCEPTION: 1130 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1131 1.1 christos "interrupt: break_exception\n"); 1132 1.1 christos break; 1133 1.1 christos case FRV_RESET: 1134 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1135 1.1 christos "interrupt: reset\n"); 1136 1.1 christos break; 1137 1.1 christos default: 1138 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1139 1.1 christos "unhandled interrupt kind: %d\n", kind); 1140 1.1 christos break; 1141 1.1 christos } 1142 1.1 christos } 1143 1.1 christos 1144 1.1 christos /* Handle a break interrupt. */ 1145 1.1 christos void 1146 1.1 christos frv_break_interrupt ( 1147 1.1 christos SIM_CPU *current_cpu, struct frv_interrupt *interrupt, IADDR current_pc 1148 1.1 christos ) 1149 1.1 christos { 1150 1.1 christos IADDR new_pc; 1151 1.1 christos 1152 1.1 christos /* BPCSR=PC 1153 1.1 christos BPSR.BS=PSR.S 1154 1.1 christos BPSR.BET=PSR.ET 1155 1.1 christos PSR.S=1 1156 1.1 christos PSR.ET=0 1157 1.1 christos TBR.TT=0xff 1158 1.1 christos PC=TBR 1159 1.1 christos */ 1160 1.1 christos /* Must set PSR.S first to allow access to supervisor-only spr registers. */ 1161 1.1 christos SET_H_BPSR_BS (GET_H_PSR_S ()); 1162 1.1 christos SET_H_BPSR_BET (GET_H_PSR_ET ()); 1163 1.1 christos SET_H_PSR_S (1); 1164 1.1 christos SET_H_PSR_ET (0); 1165 1.1 christos /* Must set PSR.S first to allow access to supervisor-only spr registers. */ 1166 1.1 christos SET_H_SPR (H_SPR_BPCSR, current_pc); 1167 1.1 christos 1168 1.1 christos /* Set the new PC in the TBR. */ 1169 1.1 christos SET_H_TBR_TT (interrupt->handler_offset); 1170 1.1 christos new_pc = GET_H_SPR (H_SPR_TBR); 1171 1.1 christos SET_H_PC (new_pc); 1172 1.1 christos 1173 1.1 christos CPU_DEBUG_STATE (current_cpu) = 1; 1174 1.1 christos } 1175 1.1 christos 1176 1.1 christos /* Handle a program interrupt or a software interrupt. */ 1177 1.1 christos void 1178 1.1 christos frv_program_or_software_interrupt ( 1179 1.1 christos SIM_CPU *current_cpu, struct frv_interrupt *interrupt, IADDR current_pc 1180 1.1 christos ) 1181 1.1 christos { 1182 1.1 christos USI new_pc; 1183 1.1 christos int original_psr_et; 1184 1.1 christos 1185 1.1 christos /* PCSR=PC 1186 1.1 christos PSR.PS=PSR.S 1187 1.1 christos PSR.ET=0 1188 1.1 christos PSR.S=1 1189 1.1 christos if PSR.ESR==1 1190 1.1 christos SR0 through SR3=GR4 through GR7 1191 1.1 christos TBR.TT=interrupt handler offset 1192 1.1 christos PC=TBR 1193 1.1 christos */ 1194 1.1 christos original_psr_et = GET_H_PSR_ET (); 1195 1.1 christos 1196 1.1 christos SET_H_PSR_PS (GET_H_PSR_S ()); 1197 1.1 christos SET_H_PSR_ET (0); 1198 1.1 christos SET_H_PSR_S (1); 1199 1.1 christos 1200 1.1 christos /* Must set PSR.S first to allow access to supervisor-only spr registers. */ 1201 1.1 christos /* The PCSR depends on the precision of the interrupt. */ 1202 1.1 christos if (interrupt->precise) 1203 1.1 christos SET_H_SPR (H_SPR_PCSR, previous_vliw_pc); 1204 1.1 christos else 1205 1.1 christos SET_H_SPR (H_SPR_PCSR, current_pc); 1206 1.1 christos 1207 1.1 christos /* Set the new PC in the TBR. */ 1208 1.1 christos SET_H_TBR_TT (interrupt->handler_offset); 1209 1.1 christos new_pc = GET_H_SPR (H_SPR_TBR); 1210 1.1 christos SET_H_PC (new_pc); 1211 1.1 christos 1212 1.1 christos /* If PSR.ET was not originally set, then enter the stopped state. */ 1213 1.1 christos if (! original_psr_et) 1214 1.1 christos { 1215 1.1 christos SIM_DESC sd = CPU_STATE (current_cpu); 1216 1.1 christos frv_non_operating_interrupt (current_cpu, interrupt->kind, current_pc); 1217 1.1 christos sim_engine_halt (sd, current_cpu, NULL, new_pc, sim_stopped, SIM_SIGINT); 1218 1.1 christos } 1219 1.1 christos } 1220 1.1 christos 1221 1.1 christos /* Handle a program interrupt or a software interrupt. */ 1222 1.1 christos void 1223 1.1 christos frv_external_interrupt ( 1224 1.1 christos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc 1225 1.1 christos ) 1226 1.1 christos { 1227 1.1 christos USI new_pc; 1228 1.1 christos struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind]; 1229 1.1 christos 1230 1.1 christos /* Don't process the interrupt if PSR.ET is not set or if it is masked. 1231 1.1 christos Interrupt 15 is processed even if it appears to be masked. */ 1232 1.1 christos if (! GET_H_PSR_ET () 1233 1.1 christos || (interrupt->kind != FRV_INTERRUPT_LEVEL_15 1234 1.1 christos && interrupt->kind < GET_H_PSR_PIL ())) 1235 1.1 christos return; /* Leave it for later. */ 1236 1.1 christos 1237 1.1 christos /* Remove the interrupt from the queue. */ 1238 1.1 christos --frv_interrupt_state.queue_index; 1239 1.1 christos 1240 1.1 christos /* PCSR=PC 1241 1.1 christos PSR.PS=PSR.S 1242 1.1 christos PSR.ET=0 1243 1.1 christos PSR.S=1 1244 1.1 christos if PSR.ESR==1 1245 1.1 christos SR0 through SR3=GR4 through GR7 1246 1.1 christos TBR.TT=interrupt handler offset 1247 1.1 christos PC=TBR 1248 1.1 christos */ 1249 1.1 christos SET_H_PSR_PS (GET_H_PSR_S ()); 1250 1.1 christos SET_H_PSR_ET (0); 1251 1.1 christos SET_H_PSR_S (1); 1252 1.1 christos /* Must set PSR.S first to allow access to supervisor-only spr registers. */ 1253 1.1 christos SET_H_SPR (H_SPR_PCSR, GET_H_PC ()); 1254 1.1 christos 1255 1.1 christos /* Set the new PC in the TBR. */ 1256 1.1 christos SET_H_TBR_TT (interrupt->handler_offset); 1257 1.1 christos new_pc = GET_H_SPR (H_SPR_TBR); 1258 1.1 christos SET_H_PC (new_pc); 1259 1.1 christos } 1260 1.1 christos 1261 1.1 christos /* Clear interrupts which fall within the range of classes given. */ 1262 1.1 christos void 1263 1.1 christos frv_clear_interrupt_classes ( 1264 1.1 christos enum frv_interrupt_class low_class, enum frv_interrupt_class high_class 1265 1.1 christos ) 1266 1.1 christos { 1267 1.1 christos int i; 1268 1.1 christos int j; 1269 1.1 christos int limit = frv_interrupt_state.queue_index; 1270 1.1 christos 1271 1.1 christos /* Find the lowest priority interrupt to be removed. */ 1272 1.1 christos for (i = 0; i < limit; ++i) 1273 1.1 christos { 1274 1.1 christos enum frv_interrupt_kind kind = frv_interrupt_state.queue[i].kind; 1275 1.1 christos struct frv_interrupt* interrupt = & frv_interrupt_table[kind]; 1276 1.1 christos if (interrupt->iclass >= low_class) 1277 1.1 christos break; 1278 1.1 christos } 1279 1.1 christos 1280 1.1 christos /* Find the highest priority interrupt to be removed. */ 1281 1.1 christos for (j = limit - 1; j >= i; --j) 1282 1.1 christos { 1283 1.1 christos enum frv_interrupt_kind kind = frv_interrupt_state.queue[j].kind; 1284 1.1 christos struct frv_interrupt* interrupt = & frv_interrupt_table[kind]; 1285 1.1 christos if (interrupt->iclass <= high_class) 1286 1.1 christos break; 1287 1.1 christos } 1288 1.1 christos 1289 1.1 christos /* Shuffle the remaining high priority interrupts down into the empty space 1290 1.1 christos left by the deleted interrupts. */ 1291 1.1 christos if (j >= i) 1292 1.1 christos { 1293 1.1 christos for (++j; j < limit; ++j) 1294 1.1 christos frv_interrupt_state.queue[i++] = frv_interrupt_state.queue[j]; 1295 1.1 christos frv_interrupt_state.queue_index -= (j - i); 1296 1.1 christos } 1297 1.1 christos } 1298 1.1 christos 1299 1.1 christos /* Save data written to memory into the interrupt state so that it can be 1300 1.1 christos copied to the appropriate EDR register, if necessary, in the event of an 1301 1.1 christos interrupt. */ 1302 1.1 christos void 1303 1.1 christos frv_save_data_written_for_interrupts ( 1304 1.1 christos SIM_CPU *current_cpu, CGEN_WRITE_QUEUE_ELEMENT *item 1305 1.1 christos ) 1306 1.1 christos { 1307 1.1 christos /* Record the slot containing the insn doing the write in the 1308 1.1 christos interrupt state. */ 1309 1.1 christos frv_interrupt_state.slot = CGEN_WRITE_QUEUE_ELEMENT_PIPE (item); 1310 1.1 christos 1311 1.1 christos /* Now record any data written to memory in the interrupt state. */ 1312 1.1 christos switch (CGEN_WRITE_QUEUE_ELEMENT_KIND (item)) 1313 1.1 christos { 1314 1.1 christos case CGEN_BI_WRITE: 1315 1.1 christos case CGEN_QI_WRITE: 1316 1.1 christos case CGEN_SI_WRITE: 1317 1.1 christos case CGEN_SF_WRITE: 1318 1.1 christos case CGEN_PC_WRITE: 1319 1.1 christos case CGEN_FN_HI_WRITE: 1320 1.1 christos case CGEN_FN_SI_WRITE: 1321 1.1 christos case CGEN_FN_SF_WRITE: 1322 1.1 christos case CGEN_FN_DI_WRITE: 1323 1.1 christos case CGEN_FN_DF_WRITE: 1324 1.1 christos case CGEN_FN_XI_WRITE: 1325 1.1 christos case CGEN_FN_PC_WRITE: 1326 1.1 christos break; /* Ignore writes to registers. */ 1327 1.1 christos case CGEN_MEM_QI_WRITE: 1328 1.1 christos frv_interrupt_state.data_written.length = 1; 1329 1.1 christos frv_interrupt_state.data_written.words[0] 1330 1.1 christos = item->kinds.mem_qi_write.value; 1331 1.1 christos break; 1332 1.1 christos case CGEN_MEM_HI_WRITE: 1333 1.1 christos frv_interrupt_state.data_written.length = 1; 1334 1.1 christos frv_interrupt_state.data_written.words[0] 1335 1.1 christos = item->kinds.mem_hi_write.value; 1336 1.1 christos break; 1337 1.1 christos case CGEN_MEM_SI_WRITE: 1338 1.1 christos frv_interrupt_state.data_written.length = 1; 1339 1.1 christos frv_interrupt_state.data_written.words[0] 1340 1.1 christos = item->kinds.mem_si_write.value; 1341 1.1 christos break; 1342 1.1 christos case CGEN_MEM_DI_WRITE: 1343 1.1 christos frv_interrupt_state.data_written.length = 2; 1344 1.1 christos frv_interrupt_state.data_written.words[0] 1345 1.1 christos = item->kinds.mem_di_write.value >> 32; 1346 1.1 christos frv_interrupt_state.data_written.words[1] 1347 1.1 christos = item->kinds.mem_di_write.value; 1348 1.1 christos break; 1349 1.1 christos case CGEN_MEM_DF_WRITE: 1350 1.1 christos frv_interrupt_state.data_written.length = 2; 1351 1.1 christos frv_interrupt_state.data_written.words[0] 1352 1.1 christos = item->kinds.mem_df_write.value >> 32; 1353 1.1 christos frv_interrupt_state.data_written.words[1] 1354 1.1 christos = item->kinds.mem_df_write.value; 1355 1.1 christos break; 1356 1.1 christos case CGEN_MEM_XI_WRITE: 1357 1.1 christos frv_interrupt_state.data_written.length = 4; 1358 1.1 christos frv_interrupt_state.data_written.words[0] 1359 1.1 christos = item->kinds.mem_xi_write.value[0]; 1360 1.1 christos frv_interrupt_state.data_written.words[1] 1361 1.1 christos = item->kinds.mem_xi_write.value[1]; 1362 1.1 christos frv_interrupt_state.data_written.words[2] 1363 1.1 christos = item->kinds.mem_xi_write.value[2]; 1364 1.1 christos frv_interrupt_state.data_written.words[3] 1365 1.1 christos = item->kinds.mem_xi_write.value[3]; 1366 1.1 christos break; 1367 1.1 christos case CGEN_FN_MEM_QI_WRITE: 1368 1.1 christos frv_interrupt_state.data_written.length = 1; 1369 1.1 christos frv_interrupt_state.data_written.words[0] 1370 1.1 christos = item->kinds.fn_mem_qi_write.value; 1371 1.1 christos break; 1372 1.1 christos case CGEN_FN_MEM_HI_WRITE: 1373 1.1 christos frv_interrupt_state.data_written.length = 1; 1374 1.1 christos frv_interrupt_state.data_written.words[0] 1375 1.1 christos = item->kinds.fn_mem_hi_write.value; 1376 1.1 christos break; 1377 1.1 christos case CGEN_FN_MEM_SI_WRITE: 1378 1.1 christos frv_interrupt_state.data_written.length = 1; 1379 1.1 christos frv_interrupt_state.data_written.words[0] 1380 1.1 christos = item->kinds.fn_mem_si_write.value; 1381 1.1 christos break; 1382 1.1 christos case CGEN_FN_MEM_DI_WRITE: 1383 1.1 christos frv_interrupt_state.data_written.length = 2; 1384 1.1 christos frv_interrupt_state.data_written.words[0] 1385 1.1 christos = item->kinds.fn_mem_di_write.value >> 32; 1386 1.1 christos frv_interrupt_state.data_written.words[1] 1387 1.1 christos = item->kinds.fn_mem_di_write.value; 1388 1.1 christos break; 1389 1.1 christos case CGEN_FN_MEM_DF_WRITE: 1390 1.1 christos frv_interrupt_state.data_written.length = 2; 1391 1.1 christos frv_interrupt_state.data_written.words[0] 1392 1.1 christos = item->kinds.fn_mem_df_write.value >> 32; 1393 1.1 christos frv_interrupt_state.data_written.words[1] 1394 1.1 christos = item->kinds.fn_mem_df_write.value; 1395 1.1 christos break; 1396 1.1 christos case CGEN_FN_MEM_XI_WRITE: 1397 1.1 christos frv_interrupt_state.data_written.length = 4; 1398 1.1 christos frv_interrupt_state.data_written.words[0] 1399 1.1 christos = item->kinds.fn_mem_xi_write.value[0]; 1400 1.1 christos frv_interrupt_state.data_written.words[1] 1401 1.1 christos = item->kinds.fn_mem_xi_write.value[1]; 1402 1.1 christos frv_interrupt_state.data_written.words[2] 1403 1.1 christos = item->kinds.fn_mem_xi_write.value[2]; 1404 1.1 christos frv_interrupt_state.data_written.words[3] 1405 1.1 christos = item->kinds.fn_mem_xi_write.value[3]; 1406 1.1 christos break; 1407 1.1 christos default: 1408 1.1 christos { 1409 1.1 christos SIM_DESC sd = CPU_STATE (current_cpu); 1410 1.1 christos IADDR pc = CPU_PC_GET (current_cpu); 1411 1.1 christos sim_engine_abort (sd, current_cpu, pc, 1412 1.1 christos "unknown write kind during save for interrupt\n"); 1413 1.1 christos } 1414 1.1 christos break; 1415 1.1 christos } 1416 1.1 christos } 1417