166e63ce3Schristos /* frv exception and interrupt support
2*1424dfb3Schristos Copyright (C) 1999-2020 Free Software Foundation, Inc.
366e63ce3Schristos Contributed by Red Hat.
466e63ce3Schristos
566e63ce3Schristos This file is part of the GNU simulators.
666e63ce3Schristos
766e63ce3Schristos This program is free software; you can redistribute it and/or modify
866e63ce3Schristos it under the terms of the GNU General Public License as published by
966e63ce3Schristos the Free Software Foundation; either version 3 of the License, or
1066e63ce3Schristos (at your option) any later version.
1166e63ce3Schristos
1266e63ce3Schristos This program is distributed in the hope that it will be useful,
1366e63ce3Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1466e63ce3Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1566e63ce3Schristos GNU General Public License for more details.
1666e63ce3Schristos
1766e63ce3Schristos You should have received a copy of the GNU General Public License
1866e63ce3Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */
1966e63ce3Schristos
2066e63ce3Schristos #define WANT_CPU frvbf
2166e63ce3Schristos #define WANT_CPU_FRVBF
2266e63ce3Schristos
2366e63ce3Schristos #include "sim-main.h"
2466e63ce3Schristos #include "bfd.h"
2566e63ce3Schristos
2666e63ce3Schristos /* FR-V Interrupt table.
2766e63ce3Schristos Describes the interrupts supported by the FR-V.
2866e63ce3Schristos This table *must* be maintained in order of interrupt priority as defined by
2966e63ce3Schristos frv_interrupt_kind. */
3066e63ce3Schristos #define DEFERRED 1
3166e63ce3Schristos #define PRECISE 1
3266e63ce3Schristos #define ITABLE_ENTRY(name, class, deferral, precision, offset) \
3366e63ce3Schristos {FRV_##name, FRV_EC_##name, class, deferral, precision, offset}
3466e63ce3Schristos
3566e63ce3Schristos struct frv_interrupt frv_interrupt_table[NUM_FRV_INTERRUPT_KINDS] =
3666e63ce3Schristos {
3766e63ce3Schristos /* External interrupts */
3866e63ce3Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_1, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x21),
3966e63ce3Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_2, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x22),
4066e63ce3Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_3, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x23),
4166e63ce3Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_4, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x24),
4266e63ce3Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_5, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x25),
4366e63ce3Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_6, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x26),
4466e63ce3Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_7, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x27),
4566e63ce3Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_8, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x28),
4666e63ce3Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_9, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x29),
4766e63ce3Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_10, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2a),
4866e63ce3Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_11, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2b),
4966e63ce3Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_12, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2c),
5066e63ce3Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_13, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2d),
5166e63ce3Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_14, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2e),
5266e63ce3Schristos ITABLE_ENTRY(INTERRUPT_LEVEL_15, FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2f),
5366e63ce3Schristos /* Software interrupt */
5466e63ce3Schristos ITABLE_ENTRY(TRAP_INSTRUCTION, FRV_SOFTWARE_INTERRUPT, !DEFERRED, !PRECISE, 0x80),
5566e63ce3Schristos /* Program interrupts */
5666e63ce3Schristos ITABLE_ENTRY(COMMIT_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x19),
5766e63ce3Schristos ITABLE_ENTRY(DIVISION_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x17),
5866e63ce3Schristos ITABLE_ENTRY(DATA_STORE_ERROR, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x14),
5966e63ce3Schristos ITABLE_ENTRY(DATA_ACCESS_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x13),
6066e63ce3Schristos ITABLE_ENTRY(DATA_ACCESS_MMU_MISS, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x12),
6166e63ce3Schristos ITABLE_ENTRY(DATA_ACCESS_ERROR, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x11),
6266e63ce3Schristos ITABLE_ENTRY(MP_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x0e),
6366e63ce3Schristos ITABLE_ENTRY(FP_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x0d),
6466e63ce3Schristos ITABLE_ENTRY(MEM_ADDRESS_NOT_ALIGNED, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x10),
6566e63ce3Schristos ITABLE_ENTRY(REGISTER_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x08),
6666e63ce3Schristos ITABLE_ENTRY(MP_DISABLED, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x0b),
6766e63ce3Schristos ITABLE_ENTRY(FP_DISABLED, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x0a),
6866e63ce3Schristos ITABLE_ENTRY(PRIVILEGED_INSTRUCTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x06),
6966e63ce3Schristos ITABLE_ENTRY(ILLEGAL_INSTRUCTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x07),
7066e63ce3Schristos ITABLE_ENTRY(INSTRUCTION_ACCESS_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x03),
7166e63ce3Schristos ITABLE_ENTRY(INSTRUCTION_ACCESS_ERROR, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x02),
7266e63ce3Schristos ITABLE_ENTRY(INSTRUCTION_ACCESS_MMU_MISS, FRV_PROGRAM_INTERRUPT, !DEFERRED, PRECISE, 0x01),
7366e63ce3Schristos ITABLE_ENTRY(COMPOUND_EXCEPTION, FRV_PROGRAM_INTERRUPT, !DEFERRED, !PRECISE, 0x20),
7466e63ce3Schristos /* Break interrupt */
7566e63ce3Schristos ITABLE_ENTRY(BREAK_EXCEPTION, FRV_BREAK_INTERRUPT, !DEFERRED, !PRECISE, 0xff),
7666e63ce3Schristos /* Reset interrupt */
7766e63ce3Schristos ITABLE_ENTRY(RESET, FRV_RESET_INTERRUPT, !DEFERRED, !PRECISE, 0x00)
7866e63ce3Schristos };
7966e63ce3Schristos
8066e63ce3Schristos /* The current interrupt state. */
8166e63ce3Schristos struct frv_interrupt_state frv_interrupt_state;
8266e63ce3Schristos
8366e63ce3Schristos /* maintain the address of the start of the previous VLIW insn sequence. */
8466e63ce3Schristos IADDR previous_vliw_pc;
8566e63ce3Schristos
8666e63ce3Schristos /* Add a break interrupt to the interrupt queue. */
8766e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_break_interrupt(SIM_CPU * current_cpu)8866e63ce3Schristos frv_queue_break_interrupt (SIM_CPU *current_cpu)
8966e63ce3Schristos {
9066e63ce3Schristos return frv_queue_interrupt (current_cpu, FRV_BREAK_EXCEPTION);
9166e63ce3Schristos }
9266e63ce3Schristos
9366e63ce3Schristos /* Add a software interrupt to the interrupt queue. */
9466e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_software_interrupt(SIM_CPU * current_cpu,SI offset)9566e63ce3Schristos frv_queue_software_interrupt (SIM_CPU *current_cpu, SI offset)
9666e63ce3Schristos {
9766e63ce3Schristos struct frv_interrupt_queue_element *new_element
9866e63ce3Schristos = frv_queue_interrupt (current_cpu, FRV_TRAP_INSTRUCTION);
9966e63ce3Schristos
10066e63ce3Schristos struct frv_interrupt *interrupt = & frv_interrupt_table[new_element->kind];
10166e63ce3Schristos interrupt->handler_offset = offset;
10266e63ce3Schristos
10366e63ce3Schristos return new_element;
10466e63ce3Schristos }
10566e63ce3Schristos
10666e63ce3Schristos /* Add a program interrupt to the interrupt queue. */
10766e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_program_interrupt(SIM_CPU * current_cpu,enum frv_interrupt_kind kind)10866e63ce3Schristos frv_queue_program_interrupt (
10966e63ce3Schristos SIM_CPU *current_cpu, enum frv_interrupt_kind kind
11066e63ce3Schristos )
11166e63ce3Schristos {
11266e63ce3Schristos return frv_queue_interrupt (current_cpu, kind);
11366e63ce3Schristos }
11466e63ce3Schristos
11566e63ce3Schristos /* Add an external interrupt to the interrupt queue. */
11666e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_external_interrupt(SIM_CPU * current_cpu,enum frv_interrupt_kind kind)11766e63ce3Schristos frv_queue_external_interrupt (
11866e63ce3Schristos SIM_CPU *current_cpu, enum frv_interrupt_kind kind
11966e63ce3Schristos )
12066e63ce3Schristos {
12166e63ce3Schristos if (! GET_H_PSR_ET ()
12266e63ce3Schristos || (kind != FRV_INTERRUPT_LEVEL_15 && kind < GET_H_PSR_PIL ()))
12366e63ce3Schristos return NULL; /* Leave it for later. */
12466e63ce3Schristos
12566e63ce3Schristos return frv_queue_interrupt (current_cpu, kind);
12666e63ce3Schristos }
12766e63ce3Schristos
12866e63ce3Schristos /* Add any interrupt to the interrupt queue. It will be added in reverse
12966e63ce3Schristos priority order. This makes it easy to find the highest priority interrupt
13066e63ce3Schristos at the end of the queue and to remove it after processing. */
13166e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_interrupt(SIM_CPU * current_cpu,enum frv_interrupt_kind kind)13266e63ce3Schristos frv_queue_interrupt (SIM_CPU *current_cpu, enum frv_interrupt_kind kind)
13366e63ce3Schristos {
13466e63ce3Schristos int i;
13566e63ce3Schristos int j;
13666e63ce3Schristos int limit = frv_interrupt_state.queue_index;
13766e63ce3Schristos struct frv_interrupt_queue_element *new_element;
13866e63ce3Schristos enum frv_interrupt_class iclass;
13966e63ce3Schristos
14066e63ce3Schristos if (limit >= FRV_INTERRUPT_QUEUE_SIZE)
14166e63ce3Schristos abort (); /* TODO: Make the queue dynamic */
14266e63ce3Schristos
14366e63ce3Schristos /* Find the right place in the queue. */
14466e63ce3Schristos for (i = 0; i < limit; ++i)
14566e63ce3Schristos {
14666e63ce3Schristos if (frv_interrupt_state.queue[i].kind >= kind)
14766e63ce3Schristos break;
14866e63ce3Schristos }
14966e63ce3Schristos
15066e63ce3Schristos /* Don't queue two external interrupts of the same priority. */
15166e63ce3Schristos iclass = frv_interrupt_table[kind].iclass;
15266e63ce3Schristos if (i < limit && iclass == FRV_EXTERNAL_INTERRUPT)
15366e63ce3Schristos {
15466e63ce3Schristos if (frv_interrupt_state.queue[i].kind == kind)
15566e63ce3Schristos return & frv_interrupt_state.queue[i];
15666e63ce3Schristos }
15766e63ce3Schristos
15866e63ce3Schristos /* Make room for the new interrupt in this spot. */
15966e63ce3Schristos for (j = limit - 1; j >= i; --j)
16066e63ce3Schristos frv_interrupt_state.queue[j + 1] = frv_interrupt_state.queue[j];
16166e63ce3Schristos
16266e63ce3Schristos /* Add the new interrupt. */
16366e63ce3Schristos frv_interrupt_state.queue_index++;
16466e63ce3Schristos new_element = & frv_interrupt_state.queue[i];
16566e63ce3Schristos new_element->kind = kind;
16666e63ce3Schristos new_element->vpc = CPU_PC_GET (current_cpu);
16766e63ce3Schristos new_element->u.data_written.length = 0;
16866e63ce3Schristos frv_set_interrupt_queue_slot (current_cpu, new_element);
16966e63ce3Schristos
17066e63ce3Schristos return new_element;
17166e63ce3Schristos }
17266e63ce3Schristos
17366e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_register_exception_interrupt(SIM_CPU * current_cpu,enum frv_rec rec)17466e63ce3Schristos frv_queue_register_exception_interrupt (SIM_CPU *current_cpu, enum frv_rec rec)
17566e63ce3Schristos {
17666e63ce3Schristos struct frv_interrupt_queue_element *new_element =
17766e63ce3Schristos frv_queue_program_interrupt (current_cpu, FRV_REGISTER_EXCEPTION);
17866e63ce3Schristos
17966e63ce3Schristos new_element->u.rec = rec;
18066e63ce3Schristos
18166e63ce3Schristos return new_element;
18266e63ce3Schristos }
18366e63ce3Schristos
18466e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_mem_address_not_aligned_interrupt(SIM_CPU * current_cpu,USI addr)18566e63ce3Schristos frv_queue_mem_address_not_aligned_interrupt (SIM_CPU *current_cpu, USI addr)
18666e63ce3Schristos {
18766e63ce3Schristos struct frv_interrupt_queue_element *new_element;
18866e63ce3Schristos USI isr = GET_ISR ();
18966e63ce3Schristos
19066e63ce3Schristos /* Make sure that this exception is not masked. */
19166e63ce3Schristos if (GET_ISR_EMAM (isr))
19266e63ce3Schristos return NULL;
19366e63ce3Schristos
19466e63ce3Schristos /* Queue the interrupt. */
19566e63ce3Schristos new_element = frv_queue_program_interrupt (current_cpu,
19666e63ce3Schristos FRV_MEM_ADDRESS_NOT_ALIGNED);
19766e63ce3Schristos new_element->eaddress = addr;
19866e63ce3Schristos new_element->u.data_written = frv_interrupt_state.data_written;
19966e63ce3Schristos frv_interrupt_state.data_written.length = 0;
20066e63ce3Schristos
20166e63ce3Schristos return new_element;
20266e63ce3Schristos }
20366e63ce3Schristos
20466e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_data_access_error_interrupt(SIM_CPU * current_cpu,USI addr)20566e63ce3Schristos frv_queue_data_access_error_interrupt (SIM_CPU *current_cpu, USI addr)
20666e63ce3Schristos {
20766e63ce3Schristos struct frv_interrupt_queue_element *new_element;
20866e63ce3Schristos new_element = frv_queue_program_interrupt (current_cpu,
20966e63ce3Schristos FRV_DATA_ACCESS_ERROR);
21066e63ce3Schristos new_element->eaddress = addr;
21166e63ce3Schristos return new_element;
21266e63ce3Schristos }
21366e63ce3Schristos
21466e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_data_access_exception_interrupt(SIM_CPU * current_cpu)21566e63ce3Schristos frv_queue_data_access_exception_interrupt (SIM_CPU *current_cpu)
21666e63ce3Schristos {
21766e63ce3Schristos return frv_queue_program_interrupt (current_cpu, FRV_DATA_ACCESS_EXCEPTION);
21866e63ce3Schristos }
21966e63ce3Schristos
22066e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_instruction_access_error_interrupt(SIM_CPU * current_cpu)22166e63ce3Schristos frv_queue_instruction_access_error_interrupt (SIM_CPU *current_cpu)
22266e63ce3Schristos {
22366e63ce3Schristos return frv_queue_program_interrupt (current_cpu, FRV_INSTRUCTION_ACCESS_ERROR);
22466e63ce3Schristos }
22566e63ce3Schristos
22666e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_instruction_access_exception_interrupt(SIM_CPU * current_cpu)22766e63ce3Schristos frv_queue_instruction_access_exception_interrupt (SIM_CPU *current_cpu)
22866e63ce3Schristos {
22966e63ce3Schristos return frv_queue_program_interrupt (current_cpu, FRV_INSTRUCTION_ACCESS_EXCEPTION);
23066e63ce3Schristos }
23166e63ce3Schristos
23266e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_illegal_instruction_interrupt(SIM_CPU * current_cpu,const CGEN_INSN * insn)23366e63ce3Schristos frv_queue_illegal_instruction_interrupt (
23466e63ce3Schristos SIM_CPU *current_cpu, const CGEN_INSN *insn
23566e63ce3Schristos )
23666e63ce3Schristos {
23766e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
23866e63ce3Schristos switch (STATE_ARCHITECTURE (sd)->mach)
23966e63ce3Schristos {
24066e63ce3Schristos case bfd_mach_fr400:
24166e63ce3Schristos case bfd_mach_fr450:
24266e63ce3Schristos case bfd_mach_fr550:
24366e63ce3Schristos break;
24466e63ce3Schristos default:
24566e63ce3Schristos /* Some machines generate fp_exception for this case. */
24666e63ce3Schristos if (frv_is_float_insn (insn) || frv_is_media_insn (insn))
24766e63ce3Schristos {
24866e63ce3Schristos struct frv_fp_exception_info fp_info = {
24966e63ce3Schristos FSR_NO_EXCEPTION, FTT_SEQUENCE_ERROR
25066e63ce3Schristos };
25166e63ce3Schristos return frv_queue_fp_exception_interrupt (current_cpu, & fp_info);
25266e63ce3Schristos }
25366e63ce3Schristos break;
25466e63ce3Schristos }
25566e63ce3Schristos
25666e63ce3Schristos return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
25766e63ce3Schristos }
25866e63ce3Schristos
25966e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_privileged_instruction_interrupt(SIM_CPU * current_cpu,const CGEN_INSN * insn)26066e63ce3Schristos frv_queue_privileged_instruction_interrupt (SIM_CPU *current_cpu, const CGEN_INSN *insn)
26166e63ce3Schristos {
26266e63ce3Schristos /* The fr550 has no privileged instruction interrupt. It uses
26366e63ce3Schristos illegal_instruction. */
26466e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
26566e63ce3Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
26666e63ce3Schristos return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
26766e63ce3Schristos
26866e63ce3Schristos return frv_queue_program_interrupt (current_cpu, FRV_PRIVILEGED_INSTRUCTION);
26966e63ce3Schristos }
27066e63ce3Schristos
27166e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_float_disabled_interrupt(SIM_CPU * current_cpu)27266e63ce3Schristos frv_queue_float_disabled_interrupt (SIM_CPU *current_cpu)
27366e63ce3Schristos {
27466e63ce3Schristos /* The fr550 has no fp_disabled interrupt. It uses illegal_instruction. */
27566e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
27666e63ce3Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
27766e63ce3Schristos return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
27866e63ce3Schristos
27966e63ce3Schristos return frv_queue_program_interrupt (current_cpu, FRV_FP_DISABLED);
28066e63ce3Schristos }
28166e63ce3Schristos
28266e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_media_disabled_interrupt(SIM_CPU * current_cpu)28366e63ce3Schristos frv_queue_media_disabled_interrupt (SIM_CPU *current_cpu)
28466e63ce3Schristos {
28566e63ce3Schristos /* The fr550 has no mp_disabled interrupt. It uses illegal_instruction. */
28666e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
28766e63ce3Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
28866e63ce3Schristos return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
28966e63ce3Schristos
29066e63ce3Schristos return frv_queue_program_interrupt (current_cpu, FRV_MP_DISABLED);
29166e63ce3Schristos }
29266e63ce3Schristos
29366e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_non_implemented_instruction_interrupt(SIM_CPU * current_cpu,const CGEN_INSN * insn)29466e63ce3Schristos frv_queue_non_implemented_instruction_interrupt (
29566e63ce3Schristos SIM_CPU *current_cpu, const CGEN_INSN *insn
29666e63ce3Schristos )
29766e63ce3Schristos {
29866e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
29966e63ce3Schristos switch (STATE_ARCHITECTURE (sd)->mach)
30066e63ce3Schristos {
30166e63ce3Schristos case bfd_mach_fr400:
30266e63ce3Schristos case bfd_mach_fr450:
30366e63ce3Schristos case bfd_mach_fr550:
30466e63ce3Schristos break;
30566e63ce3Schristos default:
30666e63ce3Schristos /* Some machines generate fp_exception or mp_exception for this case. */
30766e63ce3Schristos if (frv_is_float_insn (insn))
30866e63ce3Schristos {
30966e63ce3Schristos struct frv_fp_exception_info fp_info = {
31066e63ce3Schristos FSR_NO_EXCEPTION, FTT_UNIMPLEMENTED_FPOP
31166e63ce3Schristos };
31266e63ce3Schristos return frv_queue_fp_exception_interrupt (current_cpu, & fp_info);
31366e63ce3Schristos }
31466e63ce3Schristos if (frv_is_media_insn (insn))
31566e63ce3Schristos {
31666e63ce3Schristos frv_set_mp_exception_registers (current_cpu, MTT_UNIMPLEMENTED_MPOP,
31766e63ce3Schristos 0);
31866e63ce3Schristos return NULL; /* no interrupt queued at this time. */
31966e63ce3Schristos }
32066e63ce3Schristos break;
32166e63ce3Schristos }
32266e63ce3Schristos
32366e63ce3Schristos return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
32466e63ce3Schristos }
32566e63ce3Schristos
32666e63ce3Schristos /* Queue the given fp_exception interrupt. Also update fp_info by removing
32766e63ce3Schristos masked interrupts and updating the 'slot' flield. */
32866e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_fp_exception_interrupt(SIM_CPU * current_cpu,struct frv_fp_exception_info * fp_info)32966e63ce3Schristos frv_queue_fp_exception_interrupt (
33066e63ce3Schristos SIM_CPU *current_cpu, struct frv_fp_exception_info *fp_info
33166e63ce3Schristos )
33266e63ce3Schristos {
33366e63ce3Schristos SI fsr0 = GET_FSR (0);
33466e63ce3Schristos int tem = GET_FSR_TEM (fsr0);
33566e63ce3Schristos int aexc = GET_FSR_AEXC (fsr0);
33666e63ce3Schristos struct frv_interrupt_queue_element *new_element = NULL;
33766e63ce3Schristos
33866e63ce3Schristos /* Update AEXC with the interrupts that are masked. */
33966e63ce3Schristos aexc |= fp_info->fsr_mask & ~tem;
34066e63ce3Schristos SET_FSR_AEXC (fsr0, aexc);
34166e63ce3Schristos SET_FSR (0, fsr0);
34266e63ce3Schristos
34366e63ce3Schristos /* update fsr_mask with the exceptions that are enabled. */
34466e63ce3Schristos fp_info->fsr_mask &= tem;
34566e63ce3Schristos
34666e63ce3Schristos /* If there is an unmasked interrupt then queue it, unless
34766e63ce3Schristos this was a non-excepting insn, in which case simply set the NE
34866e63ce3Schristos status registers. */
34966e63ce3Schristos if (frv_interrupt_state.ne_index != NE_NOFLAG
35066e63ce3Schristos && fp_info->fsr_mask != FSR_NO_EXCEPTION)
35166e63ce3Schristos {
35266e63ce3Schristos SET_NE_FLAG (frv_interrupt_state.f_ne_flags,
35366e63ce3Schristos frv_interrupt_state.ne_index);
35466e63ce3Schristos /* TODO -- Set NESR for chips which support it. */
35566e63ce3Schristos new_element = NULL;
35666e63ce3Schristos }
35766e63ce3Schristos else if (fp_info->fsr_mask != FSR_NO_EXCEPTION
35866e63ce3Schristos || fp_info->ftt == FTT_UNIMPLEMENTED_FPOP
35966e63ce3Schristos || fp_info->ftt == FTT_SEQUENCE_ERROR
36066e63ce3Schristos || fp_info->ftt == FTT_INVALID_FR)
36166e63ce3Schristos {
36266e63ce3Schristos new_element = frv_queue_program_interrupt (current_cpu, FRV_FP_EXCEPTION);
36366e63ce3Schristos new_element->u.fp_info = *fp_info;
36466e63ce3Schristos }
36566e63ce3Schristos
36666e63ce3Schristos return new_element;
36766e63ce3Schristos }
36866e63ce3Schristos
36966e63ce3Schristos struct frv_interrupt_queue_element *
frv_queue_division_exception_interrupt(SIM_CPU * current_cpu,enum frv_dtt dtt)37066e63ce3Schristos frv_queue_division_exception_interrupt (SIM_CPU *current_cpu, enum frv_dtt dtt)
37166e63ce3Schristos {
37266e63ce3Schristos struct frv_interrupt_queue_element *new_element =
37366e63ce3Schristos frv_queue_program_interrupt (current_cpu, FRV_DIVISION_EXCEPTION);
37466e63ce3Schristos
37566e63ce3Schristos new_element->u.dtt = dtt;
37666e63ce3Schristos
37766e63ce3Schristos return new_element;
37866e63ce3Schristos }
37966e63ce3Schristos
38066e63ce3Schristos /* Check for interrupts caused by illegal insn access. These conditions are
38166e63ce3Schristos checked in the order specified by the fr400 and fr500 LSI specs. */
38266e63ce3Schristos void
frv_detect_insn_access_interrupts(SIM_CPU * current_cpu,SCACHE * sc)38366e63ce3Schristos frv_detect_insn_access_interrupts (SIM_CPU *current_cpu, SCACHE *sc)
38466e63ce3Schristos {
38566e63ce3Schristos
38666e63ce3Schristos const CGEN_INSN *insn = sc->argbuf.idesc->idata;
38766e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
38866e63ce3Schristos FRV_VLIW *vliw = CPU_VLIW (current_cpu);
38966e63ce3Schristos
39066e63ce3Schristos /* Check for vliw constraints. */
39166e63ce3Schristos if (vliw->constraint_violation)
39266e63ce3Schristos frv_queue_illegal_instruction_interrupt (current_cpu, insn);
39366e63ce3Schristos /* Check for non-excepting insns. */
39466e63ce3Schristos else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_NON_EXCEPTING)
39566e63ce3Schristos && ! GET_H_PSR_NEM ())
39666e63ce3Schristos frv_queue_non_implemented_instruction_interrupt (current_cpu, insn);
39766e63ce3Schristos /* Check for conditional insns. */
39866e63ce3Schristos else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONDITIONAL)
39966e63ce3Schristos && ! GET_H_PSR_CM ())
40066e63ce3Schristos frv_queue_non_implemented_instruction_interrupt (current_cpu, insn);
40166e63ce3Schristos /* Make sure floating point support is enabled. */
40266e63ce3Schristos else if (! GET_H_PSR_EF ())
40366e63ce3Schristos {
40466e63ce3Schristos /* Generate fp_disabled if it is a floating point insn or if PSR.EM is
40566e63ce3Schristos off and the insns accesses a fp register. */
40666e63ce3Schristos if (frv_is_float_insn (insn)
40766e63ce3Schristos || (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR_ACCESS)
40866e63ce3Schristos && ! GET_H_PSR_EM ()))
40966e63ce3Schristos frv_queue_float_disabled_interrupt (current_cpu);
41066e63ce3Schristos }
41166e63ce3Schristos /* Make sure media support is enabled. */
41266e63ce3Schristos else if (! GET_H_PSR_EM ())
41366e63ce3Schristos {
41466e63ce3Schristos /* Generate mp_disabled if it is a media insn. */
41566e63ce3Schristos if (frv_is_media_insn (insn) || CGEN_INSN_NUM (insn) == FRV_INSN_MTRAP)
41666e63ce3Schristos frv_queue_media_disabled_interrupt (current_cpu);
41766e63ce3Schristos }
41866e63ce3Schristos /* Check for privileged insns. */
41966e63ce3Schristos else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_PRIVILEGED) &&
42066e63ce3Schristos ! GET_H_PSR_S ())
42166e63ce3Schristos frv_queue_privileged_instruction_interrupt (current_cpu, insn);
42266e63ce3Schristos #if 0 /* disable for now until we find out how FSR0.QNE gets reset. */
42366e63ce3Schristos else
42466e63ce3Schristos {
42566e63ce3Schristos /* Enter the halt state if FSR0.QNE is set and we are executing a
42666e63ce3Schristos floating point insn, a media insn or an insn which access a FR
42766e63ce3Schristos register. */
42866e63ce3Schristos SI fsr0 = GET_FSR (0);
42966e63ce3Schristos if (GET_FSR_QNE (fsr0)
43066e63ce3Schristos && (frv_is_float_insn (insn) || frv_is_media_insn (insn)
43166e63ce3Schristos || CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR_ACCESS)))
43266e63ce3Schristos {
43366e63ce3Schristos sim_engine_halt (sd, current_cpu, NULL, GET_H_PC (), sim_stopped,
43466e63ce3Schristos SIM_SIGINT);
43566e63ce3Schristos }
43666e63ce3Schristos }
43766e63ce3Schristos #endif
43866e63ce3Schristos }
43966e63ce3Schristos
44066e63ce3Schristos /* Record the current VLIW slot in the given interrupt queue element. */
44166e63ce3Schristos void
frv_set_interrupt_queue_slot(SIM_CPU * current_cpu,struct frv_interrupt_queue_element * item)44266e63ce3Schristos frv_set_interrupt_queue_slot (
44366e63ce3Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
44466e63ce3Schristos )
44566e63ce3Schristos {
44666e63ce3Schristos FRV_VLIW *vliw = CPU_VLIW (current_cpu);
44766e63ce3Schristos int slot = vliw->next_slot - 1;
44866e63ce3Schristos item->slot = (*vliw->current_vliw)[slot];
44966e63ce3Schristos }
45066e63ce3Schristos
45166e63ce3Schristos /* Handle an individual interrupt. */
45266e63ce3Schristos static void
handle_interrupt(SIM_CPU * current_cpu,IADDR pc)45366e63ce3Schristos handle_interrupt (SIM_CPU *current_cpu, IADDR pc)
45466e63ce3Schristos {
45566e63ce3Schristos struct frv_interrupt *interrupt;
45666e63ce3Schristos int writeback_done = 0;
45766e63ce3Schristos while (1)
45866e63ce3Schristos {
45966e63ce3Schristos /* Interrupts are queued in priority order with the highest priority
46066e63ce3Schristos last. */
46166e63ce3Schristos int index = frv_interrupt_state.queue_index - 1;
46266e63ce3Schristos struct frv_interrupt_queue_element *item
46366e63ce3Schristos = & frv_interrupt_state.queue[index];
46466e63ce3Schristos interrupt = & frv_interrupt_table[item->kind];
46566e63ce3Schristos
46666e63ce3Schristos switch (interrupt->iclass)
46766e63ce3Schristos {
46866e63ce3Schristos case FRV_EXTERNAL_INTERRUPT:
46966e63ce3Schristos /* Perform writeback first. This may cause a higher priority
47066e63ce3Schristos interrupt. */
47166e63ce3Schristos if (! writeback_done)
47266e63ce3Schristos {
47366e63ce3Schristos frvbf_perform_writeback (current_cpu);
47466e63ce3Schristos writeback_done = 1;
47566e63ce3Schristos continue;
47666e63ce3Schristos }
47766e63ce3Schristos frv_external_interrupt (current_cpu, item, pc);
47866e63ce3Schristos return;
47966e63ce3Schristos case FRV_SOFTWARE_INTERRUPT:
48066e63ce3Schristos frv_interrupt_state.queue_index = index;
48166e63ce3Schristos frv_software_interrupt (current_cpu, item, pc);
48266e63ce3Schristos return;
48366e63ce3Schristos case FRV_PROGRAM_INTERRUPT:
48466e63ce3Schristos /* If the program interrupt is not strict (imprecise), then perform
48566e63ce3Schristos writeback first. This may, in turn, cause a higher priority
48666e63ce3Schristos interrupt. */
48766e63ce3Schristos if (! interrupt->precise && ! writeback_done)
48866e63ce3Schristos {
48966e63ce3Schristos frv_interrupt_state.imprecise_interrupt = item;
49066e63ce3Schristos frvbf_perform_writeback (current_cpu);
49166e63ce3Schristos writeback_done = 1;
49266e63ce3Schristos continue;
49366e63ce3Schristos }
49466e63ce3Schristos frv_interrupt_state.queue_index = index;
49566e63ce3Schristos frv_program_interrupt (current_cpu, item, pc);
49666e63ce3Schristos return;
49766e63ce3Schristos case FRV_BREAK_INTERRUPT:
49866e63ce3Schristos frv_interrupt_state.queue_index = index;
49966e63ce3Schristos frv_break_interrupt (current_cpu, interrupt, pc);
50066e63ce3Schristos return;
50166e63ce3Schristos case FRV_RESET_INTERRUPT:
50266e63ce3Schristos break;
50366e63ce3Schristos default:
50466e63ce3Schristos break;
50566e63ce3Schristos }
50666e63ce3Schristos frv_interrupt_state.queue_index = index;
50766e63ce3Schristos break; /* out of loop. */
50866e63ce3Schristos }
50966e63ce3Schristos
51066e63ce3Schristos /* We should never get here. */
51166e63ce3Schristos {
51266e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
51366e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
51466e63ce3Schristos "interrupt class not supported %d\n",
51566e63ce3Schristos interrupt->iclass);
51666e63ce3Schristos }
51766e63ce3Schristos }
51866e63ce3Schristos
51966e63ce3Schristos /* Check to see the if the RSTR.HR or RSTR.SR bits have been set. If so, handle
52066e63ce3Schristos the appropriate reset interrupt. */
52166e63ce3Schristos static int
check_reset(SIM_CPU * current_cpu,IADDR pc)52266e63ce3Schristos check_reset (SIM_CPU *current_cpu, IADDR pc)
52366e63ce3Schristos {
52466e63ce3Schristos int hsr0;
52566e63ce3Schristos int hr;
52666e63ce3Schristos int sr;
52766e63ce3Schristos SI rstr;
52866e63ce3Schristos FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
52966e63ce3Schristos IADDR address = RSTR_ADDRESS;
53066e63ce3Schristos
53166e63ce3Schristos /* We don't want this to show up in the cache statistics, so read the
53266e63ce3Schristos cache passively. */
53366e63ce3Schristos if (! frv_cache_read_passive_SI (cache, address, & rstr))
53466e63ce3Schristos rstr = sim_core_read_unaligned_4 (current_cpu, pc, read_map, address);
53566e63ce3Schristos
53666e63ce3Schristos hr = GET_RSTR_HR (rstr);
53766e63ce3Schristos sr = GET_RSTR_SR (rstr);
53866e63ce3Schristos
53966e63ce3Schristos if (! hr && ! sr)
54066e63ce3Schristos return 0; /* no reset. */
54166e63ce3Schristos
54266e63ce3Schristos /* Reinitialize the machine state. */
54366e63ce3Schristos if (hr)
54466e63ce3Schristos frv_hardware_reset (current_cpu);
54566e63ce3Schristos else
54666e63ce3Schristos frv_software_reset (current_cpu);
54766e63ce3Schristos
54866e63ce3Schristos /* Branch to the reset address. */
54966e63ce3Schristos hsr0 = GET_HSR0 ();
55066e63ce3Schristos if (GET_HSR0_SA (hsr0))
55166e63ce3Schristos SET_H_PC (0xff000000);
55266e63ce3Schristos else
55366e63ce3Schristos SET_H_PC (0);
55466e63ce3Schristos
55566e63ce3Schristos return 1; /* reset */
55666e63ce3Schristos }
55766e63ce3Schristos
55866e63ce3Schristos /* Process any pending interrupt(s) after a group of parallel insns. */
55966e63ce3Schristos void
frv_process_interrupts(SIM_CPU * current_cpu)56066e63ce3Schristos frv_process_interrupts (SIM_CPU *current_cpu)
56166e63ce3Schristos {
56266e63ce3Schristos SI NE_flags[2];
56366e63ce3Schristos /* Need to save the pc here because writeback may change it (due to a
56466e63ce3Schristos branch). */
56566e63ce3Schristos IADDR pc = CPU_PC_GET (current_cpu);
56666e63ce3Schristos
56766e63ce3Schristos /* Check for a reset before anything else. */
56866e63ce3Schristos if (check_reset (current_cpu, pc))
56966e63ce3Schristos return;
57066e63ce3Schristos
57166e63ce3Schristos /* First queue the writes for any accumulated NE flags. */
57266e63ce3Schristos if (frv_interrupt_state.f_ne_flags[0] != 0
57366e63ce3Schristos || frv_interrupt_state.f_ne_flags[1] != 0)
57466e63ce3Schristos {
57566e63ce3Schristos GET_NE_FLAGS (NE_flags, H_SPR_FNER0);
57666e63ce3Schristos NE_flags[0] |= frv_interrupt_state.f_ne_flags[0];
57766e63ce3Schristos NE_flags[1] |= frv_interrupt_state.f_ne_flags[1];
57866e63ce3Schristos SET_NE_FLAGS (H_SPR_FNER0, NE_flags);
57966e63ce3Schristos }
58066e63ce3Schristos
58166e63ce3Schristos /* If there is no interrupt pending, then perform parallel writeback. This
58266e63ce3Schristos may cause an interrupt. */
58366e63ce3Schristos if (frv_interrupt_state.queue_index <= 0)
58466e63ce3Schristos frvbf_perform_writeback (current_cpu);
58566e63ce3Schristos
58666e63ce3Schristos /* If there is an interrupt pending, then process it. */
58766e63ce3Schristos if (frv_interrupt_state.queue_index > 0)
58866e63ce3Schristos handle_interrupt (current_cpu, pc);
58966e63ce3Schristos }
59066e63ce3Schristos
59166e63ce3Schristos /* Find the next available ESR and return its index */
59266e63ce3Schristos static int
esr_for_data_access_exception(SIM_CPU * current_cpu,struct frv_interrupt_queue_element * item)59366e63ce3Schristos esr_for_data_access_exception (
59466e63ce3Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
59566e63ce3Schristos )
59666e63ce3Schristos {
59766e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
59866e63ce3Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
59966e63ce3Schristos return 8; /* Use ESR8, EPCR8. */
60066e63ce3Schristos
60166e63ce3Schristos if (item->slot == UNIT_I0)
60266e63ce3Schristos return 8; /* Use ESR8, EPCR8, EAR8, EDR8. */
60366e63ce3Schristos
60466e63ce3Schristos return 9; /* Use ESR9, EPCR9, EAR9. */
60566e63ce3Schristos }
60666e63ce3Schristos
60766e63ce3Schristos /* Set the next available EDR register with the data which was to be stored
60866e63ce3Schristos and return the index of the register. */
60966e63ce3Schristos static int
set_edr_register(SIM_CPU * current_cpu,struct frv_interrupt_queue_element * item,int edr_index)61066e63ce3Schristos set_edr_register (
61166e63ce3Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, int edr_index
61266e63ce3Schristos )
61366e63ce3Schristos {
61466e63ce3Schristos /* EDR0, EDR4 and EDR8 are available as blocks of 4.
61566e63ce3Schristos SI data uses EDR3, EDR7 and EDR11
61666e63ce3Schristos DI data uses EDR2, EDR6 and EDR10
61766e63ce3Schristos XI data uses EDR0, EDR4 and EDR8. */
61866e63ce3Schristos int i;
61966e63ce3Schristos edr_index += 4 - item->u.data_written.length;
62066e63ce3Schristos for (i = 0; i < item->u.data_written.length; ++i)
62166e63ce3Schristos SET_EDR (edr_index + i, item->u.data_written.words[i]);
62266e63ce3Schristos
62366e63ce3Schristos return edr_index;
62466e63ce3Schristos };
62566e63ce3Schristos
62666e63ce3Schristos /* Clear ESFR0, EPCRx, ESRx, EARx and EDRx. */
62766e63ce3Schristos static void
clear_exception_status_registers(SIM_CPU * current_cpu)62866e63ce3Schristos clear_exception_status_registers (SIM_CPU *current_cpu)
62966e63ce3Schristos {
63066e63ce3Schristos int i;
63166e63ce3Schristos /* It is only necessary to clear the flag bits indicating which registers
63266e63ce3Schristos are valid. */
63366e63ce3Schristos SET_ESFR (0, 0);
63466e63ce3Schristos SET_ESFR (1, 0);
63566e63ce3Schristos
63666e63ce3Schristos for (i = 0; i <= 2; ++i)
63766e63ce3Schristos {
63866e63ce3Schristos SI esr = GET_ESR (i);
63966e63ce3Schristos CLEAR_ESR_VALID (esr);
64066e63ce3Schristos SET_ESR (i, esr);
64166e63ce3Schristos }
64266e63ce3Schristos for (i = 8; i <= 15; ++i)
64366e63ce3Schristos {
64466e63ce3Schristos SI esr = GET_ESR (i);
64566e63ce3Schristos CLEAR_ESR_VALID (esr);
64666e63ce3Schristos SET_ESR (i, esr);
64766e63ce3Schristos }
64866e63ce3Schristos }
64966e63ce3Schristos
65066e63ce3Schristos /* Record state for media exception. */
65166e63ce3Schristos void
frv_set_mp_exception_registers(SIM_CPU * current_cpu,enum frv_msr_mtt mtt,int sie)65266e63ce3Schristos frv_set_mp_exception_registers (
65366e63ce3Schristos SIM_CPU *current_cpu, enum frv_msr_mtt mtt, int sie
65466e63ce3Schristos )
65566e63ce3Schristos {
65666e63ce3Schristos /* Record the interrupt factor in MSR0. */
65766e63ce3Schristos SI msr0 = GET_MSR (0);
65866e63ce3Schristos if (GET_MSR_MTT (msr0) == MTT_NONE)
65966e63ce3Schristos SET_MSR_MTT (msr0, mtt);
66066e63ce3Schristos
66166e63ce3Schristos /* Also set the OVF bit in the appropriate MSR as well as MSR0.AOVF. */
66266e63ce3Schristos if (mtt == MTT_OVERFLOW)
66366e63ce3Schristos {
66466e63ce3Schristos FRV_VLIW *vliw = CPU_VLIW (current_cpu);
66566e63ce3Schristos int slot = vliw->next_slot - 1;
66666e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
66766e63ce3Schristos
66866e63ce3Schristos /* If this insn is in the M2 slot, then set MSR1.OVF and MSR1.SIE,
66966e63ce3Schristos otherwise set MSR0.OVF and MSR0.SIE. */
67066e63ce3Schristos if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550 && (*vliw->current_vliw)[slot] == UNIT_FM1)
67166e63ce3Schristos {
67266e63ce3Schristos SI msr = GET_MSR (1);
67366e63ce3Schristos OR_MSR_SIE (msr, sie);
67466e63ce3Schristos SET_MSR_OVF (msr);
67566e63ce3Schristos SET_MSR (1, msr);
67666e63ce3Schristos }
67766e63ce3Schristos else
67866e63ce3Schristos {
67966e63ce3Schristos OR_MSR_SIE (msr0, sie);
68066e63ce3Schristos SET_MSR_OVF (msr0);
68166e63ce3Schristos }
68266e63ce3Schristos
68366e63ce3Schristos /* Generate the interrupt now if MSR0.MPEM is set on fr550 */
68466e63ce3Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550 && GET_MSR_MPEM (msr0))
68566e63ce3Schristos frv_queue_program_interrupt (current_cpu, FRV_MP_EXCEPTION);
68666e63ce3Schristos else
68766e63ce3Schristos {
68866e63ce3Schristos /* Regardless of the slot, set MSR0.AOVF. */
68966e63ce3Schristos SET_MSR_AOVF (msr0);
69066e63ce3Schristos }
69166e63ce3Schristos }
69266e63ce3Schristos
69366e63ce3Schristos SET_MSR (0, msr0);
69466e63ce3Schristos }
69566e63ce3Schristos
69666e63ce3Schristos /* Determine the correct FQ register to use for the given exception.
69766e63ce3Schristos Return -1 if a register is not available. */
69866e63ce3Schristos static int
fq_for_exception(SIM_CPU * current_cpu,struct frv_interrupt_queue_element * item)69966e63ce3Schristos fq_for_exception (
70066e63ce3Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
70166e63ce3Schristos )
70266e63ce3Schristos {
70366e63ce3Schristos SI fq;
70466e63ce3Schristos struct frv_fp_exception_info *fp_info = & item->u.fp_info;
70566e63ce3Schristos
70666e63ce3Schristos /* For fp_exception overflow, underflow or inexact, use FQ0 or FQ1. */
70766e63ce3Schristos if (fp_info->ftt == FTT_IEEE_754_EXCEPTION
70866e63ce3Schristos && (fp_info->fsr_mask & (FSR_OVERFLOW | FSR_UNDERFLOW | FSR_INEXACT)))
70966e63ce3Schristos {
71066e63ce3Schristos fq = GET_FQ (0);
71166e63ce3Schristos if (! GET_FQ_VALID (fq))
71266e63ce3Schristos return 0; /* FQ0 is available. */
71366e63ce3Schristos fq = GET_FQ (1);
71466e63ce3Schristos if (! GET_FQ_VALID (fq))
71566e63ce3Schristos return 1; /* FQ1 is available. */
71666e63ce3Schristos
71766e63ce3Schristos /* No FQ register is available */
71866e63ce3Schristos {
71966e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
72066e63ce3Schristos IADDR pc = CPU_PC_GET (current_cpu);
72166e63ce3Schristos sim_engine_abort (sd, current_cpu, pc, "No FQ register available\n");
72266e63ce3Schristos }
72366e63ce3Schristos return -1;
72466e63ce3Schristos }
72566e63ce3Schristos /* For other exceptions, use FQ2 if the insn was in slot F0/I0 and FQ3
72666e63ce3Schristos otherwise. */
72766e63ce3Schristos if (item->slot == UNIT_FM0 || item->slot == UNIT_I0)
72866e63ce3Schristos return 2;
72966e63ce3Schristos
73066e63ce3Schristos return 3;
73166e63ce3Schristos }
73266e63ce3Schristos
73366e63ce3Schristos /* Set FSR0, FQ0-FQ9, depending on the interrupt. */
73466e63ce3Schristos static void
set_fp_exception_registers(SIM_CPU * current_cpu,struct frv_interrupt_queue_element * item)73566e63ce3Schristos set_fp_exception_registers (
73666e63ce3Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
73766e63ce3Schristos )
73866e63ce3Schristos {
73966e63ce3Schristos int fq_index;
74066e63ce3Schristos SI fq;
74166e63ce3Schristos SI insn;
74266e63ce3Schristos SI fsr0;
74366e63ce3Schristos IADDR pc;
74466e63ce3Schristos struct frv_fp_exception_info *fp_info;
74566e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
74666e63ce3Schristos
74766e63ce3Schristos /* No FQ registers on fr550 */
74866e63ce3Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
74966e63ce3Schristos {
75066e63ce3Schristos /* Update the fsr. */
75166e63ce3Schristos fp_info = & item->u.fp_info;
75266e63ce3Schristos fsr0 = GET_FSR (0);
75366e63ce3Schristos SET_FSR_FTT (fsr0, fp_info->ftt);
75466e63ce3Schristos SET_FSR (0, fsr0);
75566e63ce3Schristos return;
75666e63ce3Schristos }
75766e63ce3Schristos
75866e63ce3Schristos /* Select an FQ and update it with the exception information. */
75966e63ce3Schristos fq_index = fq_for_exception (current_cpu, item);
76066e63ce3Schristos if (fq_index == -1)
76166e63ce3Schristos return;
76266e63ce3Schristos
76366e63ce3Schristos fp_info = & item->u.fp_info;
76466e63ce3Schristos fq = GET_FQ (fq_index);
76566e63ce3Schristos SET_FQ_MIV (fq, MIV_FLOAT);
76666e63ce3Schristos SET_FQ_SIE (fq, SIE_NIL);
76766e63ce3Schristos SET_FQ_FTT (fq, fp_info->ftt);
76866e63ce3Schristos SET_FQ_CEXC (fq, fp_info->fsr_mask);
76966e63ce3Schristos SET_FQ_VALID (fq);
77066e63ce3Schristos SET_FQ (fq_index, fq);
77166e63ce3Schristos
77266e63ce3Schristos /* Write the failing insn into FQx.OPC. */
77366e63ce3Schristos pc = item->vpc;
77466e63ce3Schristos insn = GETMEMSI (current_cpu, pc, pc);
77566e63ce3Schristos SET_FQ_OPC (fq_index, insn);
77666e63ce3Schristos
77766e63ce3Schristos /* Update the fsr. */
77866e63ce3Schristos fsr0 = GET_FSR (0);
77966e63ce3Schristos SET_FSR_QNE (fsr0); /* FQ not empty */
78066e63ce3Schristos SET_FSR_FTT (fsr0, fp_info->ftt);
78166e63ce3Schristos SET_FSR (0, fsr0);
78266e63ce3Schristos }
78366e63ce3Schristos
78466e63ce3Schristos /* Record the state of a division exception in the ISR. */
78566e63ce3Schristos static void
set_isr_exception_fields(SIM_CPU * current_cpu,struct frv_interrupt_queue_element * item)78666e63ce3Schristos set_isr_exception_fields (
78766e63ce3Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
78866e63ce3Schristos )
78966e63ce3Schristos {
79066e63ce3Schristos USI isr = GET_ISR ();
79166e63ce3Schristos int dtt = GET_ISR_DTT (isr);
79266e63ce3Schristos dtt |= item->u.dtt;
79366e63ce3Schristos SET_ISR_DTT (isr, dtt);
79466e63ce3Schristos SET_ISR (isr);
79566e63ce3Schristos }
79666e63ce3Schristos
79766e63ce3Schristos /* Set ESFR0, EPCRx, ESRx, EARx and EDRx, according to the given program
79866e63ce3Schristos interrupt. */
79966e63ce3Schristos static void
set_exception_status_registers(SIM_CPU * current_cpu,struct frv_interrupt_queue_element * item)80066e63ce3Schristos set_exception_status_registers (
80166e63ce3Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
80266e63ce3Schristos )
80366e63ce3Schristos {
80466e63ce3Schristos struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind];
80566e63ce3Schristos int slot = (item->vpc - previous_vliw_pc) / 4;
80666e63ce3Schristos int reg_index = -1;
80766e63ce3Schristos int set_ear = 0;
80866e63ce3Schristos int set_edr = 0;
80966e63ce3Schristos int set_daec = 0;
81066e63ce3Schristos int set_epcr = 0;
81166e63ce3Schristos SI esr = 0;
81266e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
81366e63ce3Schristos
81466e63ce3Schristos /* If the interrupt is strict (precise) or the interrupt is on the insns
81566e63ce3Schristos in the I0 pipe, then set the 0 registers. */
81666e63ce3Schristos if (interrupt->precise)
81766e63ce3Schristos {
81866e63ce3Schristos reg_index = 0;
81966e63ce3Schristos if (interrupt->kind == FRV_REGISTER_EXCEPTION)
82066e63ce3Schristos SET_ESR_REC (esr, item->u.rec);
82166e63ce3Schristos else if (interrupt->kind == FRV_INSTRUCTION_ACCESS_EXCEPTION)
82266e63ce3Schristos SET_ESR_IAEC (esr, item->u.iaec);
82366e63ce3Schristos /* For fr550, don't set epcr for precise interrupts. */
82466e63ce3Schristos if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550)
82566e63ce3Schristos set_epcr = 1;
82666e63ce3Schristos }
82766e63ce3Schristos else
82866e63ce3Schristos {
82966e63ce3Schristos switch (interrupt->kind)
83066e63ce3Schristos {
83166e63ce3Schristos case FRV_DIVISION_EXCEPTION:
83266e63ce3Schristos set_isr_exception_fields (current_cpu, item);
83366e63ce3Schristos /* fall thru to set reg_index. */
83466e63ce3Schristos case FRV_COMMIT_EXCEPTION:
83566e63ce3Schristos /* For fr550, always use ESR0. */
83666e63ce3Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
83766e63ce3Schristos reg_index = 0;
83866e63ce3Schristos else if (item->slot == UNIT_I0)
83966e63ce3Schristos reg_index = 0;
84066e63ce3Schristos else if (item->slot == UNIT_I1)
84166e63ce3Schristos reg_index = 1;
84266e63ce3Schristos set_epcr = 1;
84366e63ce3Schristos break;
84466e63ce3Schristos case FRV_DATA_STORE_ERROR:
84566e63ce3Schristos reg_index = 14; /* Use ESR14. */
84666e63ce3Schristos break;
84766e63ce3Schristos case FRV_DATA_ACCESS_ERROR:
84866e63ce3Schristos reg_index = 15; /* Use ESR15, EPCR15. */
84966e63ce3Schristos set_ear = 1;
85066e63ce3Schristos break;
85166e63ce3Schristos case FRV_DATA_ACCESS_EXCEPTION:
85266e63ce3Schristos set_daec = 1;
85366e63ce3Schristos /* fall through */
85466e63ce3Schristos case FRV_DATA_ACCESS_MMU_MISS:
85566e63ce3Schristos case FRV_MEM_ADDRESS_NOT_ALIGNED:
85666e63ce3Schristos /* Get the appropriate ESR, EPCR, EAR and EDR.
85766e63ce3Schristos EAR will be set. EDR will not be set if this is a store insn. */
85866e63ce3Schristos set_ear = 1;
85966e63ce3Schristos /* For fr550, never use EDRx. */
86066e63ce3Schristos if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550)
86166e63ce3Schristos if (item->u.data_written.length != 0)
86266e63ce3Schristos set_edr = 1;
86366e63ce3Schristos reg_index = esr_for_data_access_exception (current_cpu, item);
86466e63ce3Schristos set_epcr = 1;
86566e63ce3Schristos break;
86666e63ce3Schristos case FRV_MP_EXCEPTION:
86766e63ce3Schristos /* For fr550, use EPCR2 and ESR2. */
86866e63ce3Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
86966e63ce3Schristos {
87066e63ce3Schristos reg_index = 2;
87166e63ce3Schristos set_epcr = 1;
87266e63ce3Schristos }
87366e63ce3Schristos break; /* MSR0-1, FQ0-9 are already set. */
87466e63ce3Schristos case FRV_FP_EXCEPTION:
87566e63ce3Schristos set_fp_exception_registers (current_cpu, item);
87666e63ce3Schristos /* For fr550, use EPCR2 and ESR2. */
87766e63ce3Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
87866e63ce3Schristos {
87966e63ce3Schristos reg_index = 2;
88066e63ce3Schristos set_epcr = 1;
88166e63ce3Schristos }
88266e63ce3Schristos break;
88366e63ce3Schristos default:
88466e63ce3Schristos {
88566e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
88666e63ce3Schristos IADDR pc = CPU_PC_GET (current_cpu);
88766e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
88866e63ce3Schristos "invalid non-strict program interrupt kind: %d\n",
88966e63ce3Schristos interrupt->kind);
89066e63ce3Schristos break;
89166e63ce3Schristos }
89266e63ce3Schristos }
89366e63ce3Schristos } /* non-strict (imprecise) interrupt */
89466e63ce3Schristos
89566e63ce3Schristos /* Now fill in the selected exception status registers. */
89666e63ce3Schristos if (reg_index != -1)
89766e63ce3Schristos {
89866e63ce3Schristos /* Now set the exception status registers. */
89966e63ce3Schristos SET_ESFR_FLAG (reg_index);
90066e63ce3Schristos SET_ESR_EC (esr, interrupt->ec);
90166e63ce3Schristos
90266e63ce3Schristos if (set_epcr)
90366e63ce3Schristos {
90466e63ce3Schristos if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400)
90566e63ce3Schristos SET_EPCR (reg_index, previous_vliw_pc);
90666e63ce3Schristos else
90766e63ce3Schristos SET_EPCR (reg_index, item->vpc);
90866e63ce3Schristos }
90966e63ce3Schristos
91066e63ce3Schristos if (set_ear)
91166e63ce3Schristos {
91266e63ce3Schristos SET_EAR (reg_index, item->eaddress);
91366e63ce3Schristos SET_ESR_EAV (esr);
91466e63ce3Schristos }
91566e63ce3Schristos else
91666e63ce3Schristos CLEAR_ESR_EAV (esr);
91766e63ce3Schristos
91866e63ce3Schristos if (set_edr)
91966e63ce3Schristos {
92066e63ce3Schristos int edn = set_edr_register (current_cpu, item, 0/* EDR0-3 */);
92166e63ce3Schristos SET_ESR_EDN (esr, edn);
92266e63ce3Schristos SET_ESR_EDV (esr);
92366e63ce3Schristos }
92466e63ce3Schristos else
92566e63ce3Schristos CLEAR_ESR_EDV (esr);
92666e63ce3Schristos
92766e63ce3Schristos if (set_daec)
92866e63ce3Schristos SET_ESR_DAEC (esr, item->u.daec);
92966e63ce3Schristos
93066e63ce3Schristos SET_ESR_VALID (esr);
93166e63ce3Schristos SET_ESR (reg_index, esr);
93266e63ce3Schristos }
93366e63ce3Schristos }
93466e63ce3Schristos
93566e63ce3Schristos /* Check for compound interrupts.
93666e63ce3Schristos Returns NULL if no interrupt is to be processed. */
93766e63ce3Schristos static struct frv_interrupt *
check_for_compound_interrupt(SIM_CPU * current_cpu,struct frv_interrupt_queue_element * item)93866e63ce3Schristos check_for_compound_interrupt (
93966e63ce3Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
94066e63ce3Schristos )
94166e63ce3Schristos {
94266e63ce3Schristos struct frv_interrupt *interrupt;
94366e63ce3Schristos
94466e63ce3Schristos /* Set the exception status registers for the original interrupt. */
94566e63ce3Schristos set_exception_status_registers (current_cpu, item);
94666e63ce3Schristos interrupt = & frv_interrupt_table[item->kind];
94766e63ce3Schristos
94866e63ce3Schristos if (! interrupt->precise)
94966e63ce3Schristos {
95066e63ce3Schristos IADDR vpc = 0;
95166e63ce3Schristos int mask = 0;
95266e63ce3Schristos
95366e63ce3Schristos vpc = item->vpc;
95466e63ce3Schristos mask = (1 << item->kind);
95566e63ce3Schristos
95666e63ce3Schristos /* Look for more queued program interrupts which are non-deferred
95766e63ce3Schristos (pending inhibit), imprecise (non-strict) different than an interrupt
95866e63ce3Schristos already found and caused by a different insn. A bit mask is used
95966e63ce3Schristos to keep track of interrupts which have already been detected. */
96066e63ce3Schristos while (item != frv_interrupt_state.queue)
96166e63ce3Schristos {
96266e63ce3Schristos enum frv_interrupt_kind kind;
96366e63ce3Schristos struct frv_interrupt *next_interrupt;
96466e63ce3Schristos --item;
96566e63ce3Schristos kind = item->kind;
96666e63ce3Schristos next_interrupt = & frv_interrupt_table[kind];
96766e63ce3Schristos
96866e63ce3Schristos if (next_interrupt->iclass != FRV_PROGRAM_INTERRUPT)
96966e63ce3Schristos break; /* no program interrupts left. */
97066e63ce3Schristos
97166e63ce3Schristos if (item->vpc == vpc)
97266e63ce3Schristos continue; /* caused by the same insn. */
97366e63ce3Schristos
97466e63ce3Schristos vpc = item->vpc;
97566e63ce3Schristos if (! next_interrupt->precise && ! next_interrupt->deferred)
97666e63ce3Schristos {
97766e63ce3Schristos if (! (mask & (1 << kind)))
97866e63ce3Schristos {
97966e63ce3Schristos /* Set the exception status registers for the additional
98066e63ce3Schristos interrupt. */
98166e63ce3Schristos set_exception_status_registers (current_cpu, item);
98266e63ce3Schristos mask |= (1 << kind);
98366e63ce3Schristos interrupt = & frv_interrupt_table[FRV_COMPOUND_EXCEPTION];
98466e63ce3Schristos }
98566e63ce3Schristos }
98666e63ce3Schristos }
98766e63ce3Schristos }
98866e63ce3Schristos
98966e63ce3Schristos /* Return with either the original interrupt, a compound_exception,
99066e63ce3Schristos or no exception. */
99166e63ce3Schristos return interrupt;
99266e63ce3Schristos }
99366e63ce3Schristos
99466e63ce3Schristos /* Handle a program interrupt. */
99566e63ce3Schristos void
frv_program_interrupt(SIM_CPU * current_cpu,struct frv_interrupt_queue_element * item,IADDR pc)99666e63ce3Schristos frv_program_interrupt (
99766e63ce3Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc
99866e63ce3Schristos )
99966e63ce3Schristos {
100066e63ce3Schristos struct frv_interrupt *interrupt;
100166e63ce3Schristos
100266e63ce3Schristos clear_exception_status_registers (current_cpu);
100366e63ce3Schristos /* If two or more non-deferred imprecise (non-strict) interrupts occur
100466e63ce3Schristos on two or more insns, then generate a compound_exception. */
100566e63ce3Schristos interrupt = check_for_compound_interrupt (current_cpu, item);
100666e63ce3Schristos if (interrupt != NULL)
100766e63ce3Schristos {
100866e63ce3Schristos frv_program_or_software_interrupt (current_cpu, interrupt, pc);
100966e63ce3Schristos frv_clear_interrupt_classes (FRV_SOFTWARE_INTERRUPT,
101066e63ce3Schristos FRV_PROGRAM_INTERRUPT);
101166e63ce3Schristos }
101266e63ce3Schristos }
101366e63ce3Schristos
101466e63ce3Schristos /* Handle a software interrupt. */
101566e63ce3Schristos void
frv_software_interrupt(SIM_CPU * current_cpu,struct frv_interrupt_queue_element * item,IADDR pc)101666e63ce3Schristos frv_software_interrupt (
101766e63ce3Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc
101866e63ce3Schristos )
101966e63ce3Schristos {
102066e63ce3Schristos struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind];
102166e63ce3Schristos frv_program_or_software_interrupt (current_cpu, interrupt, pc);
102266e63ce3Schristos }
102366e63ce3Schristos
102466e63ce3Schristos /* Handle a program interrupt or a software interrupt in non-operating mode. */
102566e63ce3Schristos void
frv_non_operating_interrupt(SIM_CPU * current_cpu,enum frv_interrupt_kind kind,IADDR pc)102666e63ce3Schristos frv_non_operating_interrupt (
102766e63ce3Schristos SIM_CPU *current_cpu, enum frv_interrupt_kind kind, IADDR pc
102866e63ce3Schristos )
102966e63ce3Schristos {
103066e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
103166e63ce3Schristos switch (kind)
103266e63ce3Schristos {
103366e63ce3Schristos case FRV_INTERRUPT_LEVEL_1:
103466e63ce3Schristos case FRV_INTERRUPT_LEVEL_2:
103566e63ce3Schristos case FRV_INTERRUPT_LEVEL_3:
103666e63ce3Schristos case FRV_INTERRUPT_LEVEL_4:
103766e63ce3Schristos case FRV_INTERRUPT_LEVEL_5:
103866e63ce3Schristos case FRV_INTERRUPT_LEVEL_6:
103966e63ce3Schristos case FRV_INTERRUPT_LEVEL_7:
104066e63ce3Schristos case FRV_INTERRUPT_LEVEL_8:
104166e63ce3Schristos case FRV_INTERRUPT_LEVEL_9:
104266e63ce3Schristos case FRV_INTERRUPT_LEVEL_10:
104366e63ce3Schristos case FRV_INTERRUPT_LEVEL_11:
104466e63ce3Schristos case FRV_INTERRUPT_LEVEL_12:
104566e63ce3Schristos case FRV_INTERRUPT_LEVEL_13:
104666e63ce3Schristos case FRV_INTERRUPT_LEVEL_14:
104766e63ce3Schristos case FRV_INTERRUPT_LEVEL_15:
104866e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
104966e63ce3Schristos "interrupt: external %d\n", kind + 1);
105066e63ce3Schristos break;
105166e63ce3Schristos case FRV_TRAP_INSTRUCTION:
105266e63ce3Schristos break; /* handle as in operating mode. */
105366e63ce3Schristos case FRV_COMMIT_EXCEPTION:
105466e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
105566e63ce3Schristos "interrupt: commit_exception\n");
105666e63ce3Schristos break;
105766e63ce3Schristos case FRV_DIVISION_EXCEPTION:
105866e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
105966e63ce3Schristos "interrupt: division_exception\n");
106066e63ce3Schristos break;
106166e63ce3Schristos case FRV_DATA_STORE_ERROR:
106266e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
106366e63ce3Schristos "interrupt: data_store_error\n");
106466e63ce3Schristos break;
106566e63ce3Schristos case FRV_DATA_ACCESS_EXCEPTION:
106666e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
106766e63ce3Schristos "interrupt: data_access_exception\n");
106866e63ce3Schristos break;
106966e63ce3Schristos case FRV_DATA_ACCESS_MMU_MISS:
107066e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
107166e63ce3Schristos "interrupt: data_access_mmu_miss\n");
107266e63ce3Schristos break;
107366e63ce3Schristos case FRV_DATA_ACCESS_ERROR:
107466e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
107566e63ce3Schristos "interrupt: data_access_error\n");
107666e63ce3Schristos break;
107766e63ce3Schristos case FRV_MP_EXCEPTION:
107866e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
107966e63ce3Schristos "interrupt: mp_exception\n");
108066e63ce3Schristos break;
108166e63ce3Schristos case FRV_FP_EXCEPTION:
108266e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
108366e63ce3Schristos "interrupt: fp_exception\n");
108466e63ce3Schristos break;
108566e63ce3Schristos case FRV_MEM_ADDRESS_NOT_ALIGNED:
108666e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
108766e63ce3Schristos "interrupt: mem_address_not_aligned\n");
108866e63ce3Schristos break;
108966e63ce3Schristos case FRV_REGISTER_EXCEPTION:
109066e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
109166e63ce3Schristos "interrupt: register_exception\n");
109266e63ce3Schristos break;
109366e63ce3Schristos case FRV_MP_DISABLED:
109466e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
109566e63ce3Schristos "interrupt: mp_disabled\n");
109666e63ce3Schristos break;
109766e63ce3Schristos case FRV_FP_DISABLED:
109866e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
109966e63ce3Schristos "interrupt: fp_disabled\n");
110066e63ce3Schristos break;
110166e63ce3Schristos case FRV_PRIVILEGED_INSTRUCTION:
110266e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
110366e63ce3Schristos "interrupt: privileged_instruction\n");
110466e63ce3Schristos break;
110566e63ce3Schristos case FRV_ILLEGAL_INSTRUCTION:
110666e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
110766e63ce3Schristos "interrupt: illegal_instruction\n");
110866e63ce3Schristos break;
110966e63ce3Schristos case FRV_INSTRUCTION_ACCESS_EXCEPTION:
111066e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
111166e63ce3Schristos "interrupt: instruction_access_exception\n");
111266e63ce3Schristos break;
111366e63ce3Schristos case FRV_INSTRUCTION_ACCESS_MMU_MISS:
111466e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
111566e63ce3Schristos "interrupt: instruction_access_mmu_miss\n");
111666e63ce3Schristos break;
111766e63ce3Schristos case FRV_INSTRUCTION_ACCESS_ERROR:
111866e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
111966e63ce3Schristos "interrupt: insn_access_error\n");
112066e63ce3Schristos break;
112166e63ce3Schristos case FRV_COMPOUND_EXCEPTION:
112266e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
112366e63ce3Schristos "interrupt: compound_exception\n");
112466e63ce3Schristos break;
112566e63ce3Schristos case FRV_BREAK_EXCEPTION:
112666e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
112766e63ce3Schristos "interrupt: break_exception\n");
112866e63ce3Schristos break;
112966e63ce3Schristos case FRV_RESET:
113066e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
113166e63ce3Schristos "interrupt: reset\n");
113266e63ce3Schristos break;
113366e63ce3Schristos default:
113466e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
113566e63ce3Schristos "unhandled interrupt kind: %d\n", kind);
113666e63ce3Schristos break;
113766e63ce3Schristos }
113866e63ce3Schristos }
113966e63ce3Schristos
114066e63ce3Schristos /* Handle a break interrupt. */
114166e63ce3Schristos void
frv_break_interrupt(SIM_CPU * current_cpu,struct frv_interrupt * interrupt,IADDR current_pc)114266e63ce3Schristos frv_break_interrupt (
114366e63ce3Schristos SIM_CPU *current_cpu, struct frv_interrupt *interrupt, IADDR current_pc
114466e63ce3Schristos )
114566e63ce3Schristos {
114666e63ce3Schristos IADDR new_pc;
114766e63ce3Schristos
114866e63ce3Schristos /* BPCSR=PC
114966e63ce3Schristos BPSR.BS=PSR.S
115066e63ce3Schristos BPSR.BET=PSR.ET
115166e63ce3Schristos PSR.S=1
115266e63ce3Schristos PSR.ET=0
115366e63ce3Schristos TBR.TT=0xff
115466e63ce3Schristos PC=TBR
115566e63ce3Schristos */
115666e63ce3Schristos /* Must set PSR.S first to allow access to supervisor-only spr registers. */
115766e63ce3Schristos SET_H_BPSR_BS (GET_H_PSR_S ());
115866e63ce3Schristos SET_H_BPSR_BET (GET_H_PSR_ET ());
115966e63ce3Schristos SET_H_PSR_S (1);
116066e63ce3Schristos SET_H_PSR_ET (0);
116166e63ce3Schristos /* Must set PSR.S first to allow access to supervisor-only spr registers. */
116266e63ce3Schristos SET_H_SPR (H_SPR_BPCSR, current_pc);
116366e63ce3Schristos
116466e63ce3Schristos /* Set the new PC in the TBR. */
116566e63ce3Schristos SET_H_TBR_TT (interrupt->handler_offset);
116666e63ce3Schristos new_pc = GET_H_SPR (H_SPR_TBR);
116766e63ce3Schristos SET_H_PC (new_pc);
116866e63ce3Schristos
116966e63ce3Schristos CPU_DEBUG_STATE (current_cpu) = 1;
117066e63ce3Schristos }
117166e63ce3Schristos
117266e63ce3Schristos /* Handle a program interrupt or a software interrupt. */
117366e63ce3Schristos void
frv_program_or_software_interrupt(SIM_CPU * current_cpu,struct frv_interrupt * interrupt,IADDR current_pc)117466e63ce3Schristos frv_program_or_software_interrupt (
117566e63ce3Schristos SIM_CPU *current_cpu, struct frv_interrupt *interrupt, IADDR current_pc
117666e63ce3Schristos )
117766e63ce3Schristos {
117866e63ce3Schristos USI new_pc;
117966e63ce3Schristos int original_psr_et;
118066e63ce3Schristos
118166e63ce3Schristos /* PCSR=PC
118266e63ce3Schristos PSR.PS=PSR.S
118366e63ce3Schristos PSR.ET=0
118466e63ce3Schristos PSR.S=1
118566e63ce3Schristos if PSR.ESR==1
118666e63ce3Schristos SR0 through SR3=GR4 through GR7
118766e63ce3Schristos TBR.TT=interrupt handler offset
118866e63ce3Schristos PC=TBR
118966e63ce3Schristos */
119066e63ce3Schristos original_psr_et = GET_H_PSR_ET ();
119166e63ce3Schristos
119266e63ce3Schristos SET_H_PSR_PS (GET_H_PSR_S ());
119366e63ce3Schristos SET_H_PSR_ET (0);
119466e63ce3Schristos SET_H_PSR_S (1);
119566e63ce3Schristos
119666e63ce3Schristos /* Must set PSR.S first to allow access to supervisor-only spr registers. */
119766e63ce3Schristos /* The PCSR depends on the precision of the interrupt. */
119866e63ce3Schristos if (interrupt->precise)
119966e63ce3Schristos SET_H_SPR (H_SPR_PCSR, previous_vliw_pc);
120066e63ce3Schristos else
120166e63ce3Schristos SET_H_SPR (H_SPR_PCSR, current_pc);
120266e63ce3Schristos
120366e63ce3Schristos /* Set the new PC in the TBR. */
120466e63ce3Schristos SET_H_TBR_TT (interrupt->handler_offset);
120566e63ce3Schristos new_pc = GET_H_SPR (H_SPR_TBR);
120666e63ce3Schristos SET_H_PC (new_pc);
120766e63ce3Schristos
120866e63ce3Schristos /* If PSR.ET was not originally set, then enter the stopped state. */
120966e63ce3Schristos if (! original_psr_et)
121066e63ce3Schristos {
121166e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
121266e63ce3Schristos frv_non_operating_interrupt (current_cpu, interrupt->kind, current_pc);
121366e63ce3Schristos sim_engine_halt (sd, current_cpu, NULL, new_pc, sim_stopped, SIM_SIGINT);
121466e63ce3Schristos }
121566e63ce3Schristos }
121666e63ce3Schristos
121766e63ce3Schristos /* Handle a program interrupt or a software interrupt. */
121866e63ce3Schristos void
frv_external_interrupt(SIM_CPU * current_cpu,struct frv_interrupt_queue_element * item,IADDR pc)121966e63ce3Schristos frv_external_interrupt (
122066e63ce3Schristos SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc
122166e63ce3Schristos )
122266e63ce3Schristos {
122366e63ce3Schristos USI new_pc;
122466e63ce3Schristos struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind];
122566e63ce3Schristos
122666e63ce3Schristos /* Don't process the interrupt if PSR.ET is not set or if it is masked.
122766e63ce3Schristos Interrupt 15 is processed even if it appears to be masked. */
122866e63ce3Schristos if (! GET_H_PSR_ET ()
122966e63ce3Schristos || (interrupt->kind != FRV_INTERRUPT_LEVEL_15
123066e63ce3Schristos && interrupt->kind < GET_H_PSR_PIL ()))
123166e63ce3Schristos return; /* Leave it for later. */
123266e63ce3Schristos
123366e63ce3Schristos /* Remove the interrupt from the queue. */
123466e63ce3Schristos --frv_interrupt_state.queue_index;
123566e63ce3Schristos
123666e63ce3Schristos /* PCSR=PC
123766e63ce3Schristos PSR.PS=PSR.S
123866e63ce3Schristos PSR.ET=0
123966e63ce3Schristos PSR.S=1
124066e63ce3Schristos if PSR.ESR==1
124166e63ce3Schristos SR0 through SR3=GR4 through GR7
124266e63ce3Schristos TBR.TT=interrupt handler offset
124366e63ce3Schristos PC=TBR
124466e63ce3Schristos */
124566e63ce3Schristos SET_H_PSR_PS (GET_H_PSR_S ());
124666e63ce3Schristos SET_H_PSR_ET (0);
124766e63ce3Schristos SET_H_PSR_S (1);
124866e63ce3Schristos /* Must set PSR.S first to allow access to supervisor-only spr registers. */
124966e63ce3Schristos SET_H_SPR (H_SPR_PCSR, GET_H_PC ());
125066e63ce3Schristos
125166e63ce3Schristos /* Set the new PC in the TBR. */
125266e63ce3Schristos SET_H_TBR_TT (interrupt->handler_offset);
125366e63ce3Schristos new_pc = GET_H_SPR (H_SPR_TBR);
125466e63ce3Schristos SET_H_PC (new_pc);
125566e63ce3Schristos }
125666e63ce3Schristos
125766e63ce3Schristos /* Clear interrupts which fall within the range of classes given. */
125866e63ce3Schristos void
frv_clear_interrupt_classes(enum frv_interrupt_class low_class,enum frv_interrupt_class high_class)125966e63ce3Schristos frv_clear_interrupt_classes (
126066e63ce3Schristos enum frv_interrupt_class low_class, enum frv_interrupt_class high_class
126166e63ce3Schristos )
126266e63ce3Schristos {
126366e63ce3Schristos int i;
126466e63ce3Schristos int j;
126566e63ce3Schristos int limit = frv_interrupt_state.queue_index;
126666e63ce3Schristos
126766e63ce3Schristos /* Find the lowest priority interrupt to be removed. */
126866e63ce3Schristos for (i = 0; i < limit; ++i)
126966e63ce3Schristos {
127066e63ce3Schristos enum frv_interrupt_kind kind = frv_interrupt_state.queue[i].kind;
127166e63ce3Schristos struct frv_interrupt* interrupt = & frv_interrupt_table[kind];
127266e63ce3Schristos if (interrupt->iclass >= low_class)
127366e63ce3Schristos break;
127466e63ce3Schristos }
127566e63ce3Schristos
127666e63ce3Schristos /* Find the highest priority interrupt to be removed. */
127766e63ce3Schristos for (j = limit - 1; j >= i; --j)
127866e63ce3Schristos {
127966e63ce3Schristos enum frv_interrupt_kind kind = frv_interrupt_state.queue[j].kind;
128066e63ce3Schristos struct frv_interrupt* interrupt = & frv_interrupt_table[kind];
128166e63ce3Schristos if (interrupt->iclass <= high_class)
128266e63ce3Schristos break;
128366e63ce3Schristos }
128466e63ce3Schristos
128566e63ce3Schristos /* Shuffle the remaining high priority interrupts down into the empty space
128666e63ce3Schristos left by the deleted interrupts. */
128766e63ce3Schristos if (j >= i)
128866e63ce3Schristos {
128966e63ce3Schristos for (++j; j < limit; ++j)
129066e63ce3Schristos frv_interrupt_state.queue[i++] = frv_interrupt_state.queue[j];
129166e63ce3Schristos frv_interrupt_state.queue_index -= (j - i);
129266e63ce3Schristos }
129366e63ce3Schristos }
129466e63ce3Schristos
129566e63ce3Schristos /* Save data written to memory into the interrupt state so that it can be
129666e63ce3Schristos copied to the appropriate EDR register, if necessary, in the event of an
129766e63ce3Schristos interrupt. */
129866e63ce3Schristos void
frv_save_data_written_for_interrupts(SIM_CPU * current_cpu,CGEN_WRITE_QUEUE_ELEMENT * item)129966e63ce3Schristos frv_save_data_written_for_interrupts (
130066e63ce3Schristos SIM_CPU *current_cpu, CGEN_WRITE_QUEUE_ELEMENT *item
130166e63ce3Schristos )
130266e63ce3Schristos {
130366e63ce3Schristos /* Record the slot containing the insn doing the write in the
130466e63ce3Schristos interrupt state. */
130566e63ce3Schristos frv_interrupt_state.slot = CGEN_WRITE_QUEUE_ELEMENT_PIPE (item);
130666e63ce3Schristos
130766e63ce3Schristos /* Now record any data written to memory in the interrupt state. */
130866e63ce3Schristos switch (CGEN_WRITE_QUEUE_ELEMENT_KIND (item))
130966e63ce3Schristos {
131066e63ce3Schristos case CGEN_BI_WRITE:
131166e63ce3Schristos case CGEN_QI_WRITE:
131266e63ce3Schristos case CGEN_SI_WRITE:
131366e63ce3Schristos case CGEN_SF_WRITE:
131466e63ce3Schristos case CGEN_PC_WRITE:
131566e63ce3Schristos case CGEN_FN_HI_WRITE:
131666e63ce3Schristos case CGEN_FN_SI_WRITE:
131766e63ce3Schristos case CGEN_FN_SF_WRITE:
131866e63ce3Schristos case CGEN_FN_DI_WRITE:
131966e63ce3Schristos case CGEN_FN_DF_WRITE:
132066e63ce3Schristos case CGEN_FN_XI_WRITE:
132166e63ce3Schristos case CGEN_FN_PC_WRITE:
132266e63ce3Schristos break; /* Ignore writes to registers. */
132366e63ce3Schristos case CGEN_MEM_QI_WRITE:
132466e63ce3Schristos frv_interrupt_state.data_written.length = 1;
132566e63ce3Schristos frv_interrupt_state.data_written.words[0]
132666e63ce3Schristos = item->kinds.mem_qi_write.value;
132766e63ce3Schristos break;
132866e63ce3Schristos case CGEN_MEM_HI_WRITE:
132966e63ce3Schristos frv_interrupt_state.data_written.length = 1;
133066e63ce3Schristos frv_interrupt_state.data_written.words[0]
133166e63ce3Schristos = item->kinds.mem_hi_write.value;
133266e63ce3Schristos break;
133366e63ce3Schristos case CGEN_MEM_SI_WRITE:
133466e63ce3Schristos frv_interrupt_state.data_written.length = 1;
133566e63ce3Schristos frv_interrupt_state.data_written.words[0]
133666e63ce3Schristos = item->kinds.mem_si_write.value;
133766e63ce3Schristos break;
133866e63ce3Schristos case CGEN_MEM_DI_WRITE:
133966e63ce3Schristos frv_interrupt_state.data_written.length = 2;
134066e63ce3Schristos frv_interrupt_state.data_written.words[0]
134166e63ce3Schristos = item->kinds.mem_di_write.value >> 32;
134266e63ce3Schristos frv_interrupt_state.data_written.words[1]
134366e63ce3Schristos = item->kinds.mem_di_write.value;
134466e63ce3Schristos break;
134566e63ce3Schristos case CGEN_MEM_DF_WRITE:
134666e63ce3Schristos frv_interrupt_state.data_written.length = 2;
134766e63ce3Schristos frv_interrupt_state.data_written.words[0]
134866e63ce3Schristos = item->kinds.mem_df_write.value >> 32;
134966e63ce3Schristos frv_interrupt_state.data_written.words[1]
135066e63ce3Schristos = item->kinds.mem_df_write.value;
135166e63ce3Schristos break;
135266e63ce3Schristos case CGEN_MEM_XI_WRITE:
135366e63ce3Schristos frv_interrupt_state.data_written.length = 4;
135466e63ce3Schristos frv_interrupt_state.data_written.words[0]
135566e63ce3Schristos = item->kinds.mem_xi_write.value[0];
135666e63ce3Schristos frv_interrupt_state.data_written.words[1]
135766e63ce3Schristos = item->kinds.mem_xi_write.value[1];
135866e63ce3Schristos frv_interrupt_state.data_written.words[2]
135966e63ce3Schristos = item->kinds.mem_xi_write.value[2];
136066e63ce3Schristos frv_interrupt_state.data_written.words[3]
136166e63ce3Schristos = item->kinds.mem_xi_write.value[3];
136266e63ce3Schristos break;
136366e63ce3Schristos case CGEN_FN_MEM_QI_WRITE:
136466e63ce3Schristos frv_interrupt_state.data_written.length = 1;
136566e63ce3Schristos frv_interrupt_state.data_written.words[0]
136666e63ce3Schristos = item->kinds.fn_mem_qi_write.value;
136766e63ce3Schristos break;
136866e63ce3Schristos case CGEN_FN_MEM_HI_WRITE:
136966e63ce3Schristos frv_interrupt_state.data_written.length = 1;
137066e63ce3Schristos frv_interrupt_state.data_written.words[0]
137166e63ce3Schristos = item->kinds.fn_mem_hi_write.value;
137266e63ce3Schristos break;
137366e63ce3Schristos case CGEN_FN_MEM_SI_WRITE:
137466e63ce3Schristos frv_interrupt_state.data_written.length = 1;
137566e63ce3Schristos frv_interrupt_state.data_written.words[0]
137666e63ce3Schristos = item->kinds.fn_mem_si_write.value;
137766e63ce3Schristos break;
137866e63ce3Schristos case CGEN_FN_MEM_DI_WRITE:
137966e63ce3Schristos frv_interrupt_state.data_written.length = 2;
138066e63ce3Schristos frv_interrupt_state.data_written.words[0]
138166e63ce3Schristos = item->kinds.fn_mem_di_write.value >> 32;
138266e63ce3Schristos frv_interrupt_state.data_written.words[1]
138366e63ce3Schristos = item->kinds.fn_mem_di_write.value;
138466e63ce3Schristos break;
138566e63ce3Schristos case CGEN_FN_MEM_DF_WRITE:
138666e63ce3Schristos frv_interrupt_state.data_written.length = 2;
138766e63ce3Schristos frv_interrupt_state.data_written.words[0]
138866e63ce3Schristos = item->kinds.fn_mem_df_write.value >> 32;
138966e63ce3Schristos frv_interrupt_state.data_written.words[1]
139066e63ce3Schristos = item->kinds.fn_mem_df_write.value;
139166e63ce3Schristos break;
139266e63ce3Schristos case CGEN_FN_MEM_XI_WRITE:
139366e63ce3Schristos frv_interrupt_state.data_written.length = 4;
139466e63ce3Schristos frv_interrupt_state.data_written.words[0]
139566e63ce3Schristos = item->kinds.fn_mem_xi_write.value[0];
139666e63ce3Schristos frv_interrupt_state.data_written.words[1]
139766e63ce3Schristos = item->kinds.fn_mem_xi_write.value[1];
139866e63ce3Schristos frv_interrupt_state.data_written.words[2]
139966e63ce3Schristos = item->kinds.fn_mem_xi_write.value[2];
140066e63ce3Schristos frv_interrupt_state.data_written.words[3]
140166e63ce3Schristos = item->kinds.fn_mem_xi_write.value[3];
140266e63ce3Schristos break;
140366e63ce3Schristos default:
140466e63ce3Schristos {
140566e63ce3Schristos SIM_DESC sd = CPU_STATE (current_cpu);
140666e63ce3Schristos IADDR pc = CPU_PC_GET (current_cpu);
140766e63ce3Schristos sim_engine_abort (sd, current_cpu, pc,
140866e63ce3Schristos "unknown write kind during save for interrupt\n");
140966e63ce3Schristos }
141066e63ce3Schristos break;
141166e63ce3Schristos }
141266e63ce3Schristos }
1413