1 /* OpenRISC exception, interrupts, syscall and trap support
2 Copyright (C) 2017-2024 Free Software Foundation, Inc.
4 This file is part of GDB, the GNU debugger.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 /* This must come before any other includes. */
22 #define WANT_CPU_OR1K32BF
27 #include "sim-signal.h"
30 /* Implement the sim invalid instruction function. This will set the error
31 effective address to that of the invalid instruction then call the
35 sim_engine_invalid_insn (SIM_CPU
*current_cpu
, IADDR cia
, SEM_PC vpc
)
37 SET_H_SYS_EEAR0 (cia
);
39 #ifdef WANT_CPU_OR1K32BF
40 or1k32bf_exception (current_cpu
, cia
, EXCEPT_ILLEGAL
);
46 /* Generate the appropriate OpenRISC fpu exception based on the status code from
49 or1k32bf_fpu_error (CGEN_FPU
* fpu
, int status
)
51 SIM_CPU
*current_cpu
= (SIM_CPU
*)fpu
->owner
;
53 /* If floating point exceptions are enabled. */
54 if (GET_H_SYS_FPCSR_FPEE() != 0)
56 /* Set all of the status flag bits. */
58 & (sim_fpu_status_invalid_snan
59 | sim_fpu_status_invalid_qnan
60 | sim_fpu_status_invalid_isi
61 | sim_fpu_status_invalid_idi
62 | sim_fpu_status_invalid_zdz
63 | sim_fpu_status_invalid_imz
64 | sim_fpu_status_invalid_cvi
65 | sim_fpu_status_invalid_cmp
66 | sim_fpu_status_invalid_sqrt
))
67 SET_H_SYS_FPCSR_IVF (1);
69 if (status
& sim_fpu_status_invalid_snan
)
70 SET_H_SYS_FPCSR_SNF (1);
72 if (status
& sim_fpu_status_invalid_qnan
)
73 SET_H_SYS_FPCSR_QNF (1);
75 if (status
& sim_fpu_status_overflow
)
76 SET_H_SYS_FPCSR_OVF (1);
78 if (status
& sim_fpu_status_underflow
)
79 SET_H_SYS_FPCSR_UNF (1);
82 & (sim_fpu_status_invalid_isi
83 | sim_fpu_status_invalid_idi
))
84 SET_H_SYS_FPCSR_INF (1);
86 if (status
& sim_fpu_status_invalid_div0
)
87 SET_H_SYS_FPCSR_DZF (1);
89 if (status
& sim_fpu_status_inexact
)
90 SET_H_SYS_FPCSR_IXF (1);
92 /* If any of the exception bits were actually set. */
94 & (SPR_FIELD_MASK_SYS_FPCSR_IVF
95 | SPR_FIELD_MASK_SYS_FPCSR_SNF
96 | SPR_FIELD_MASK_SYS_FPCSR_QNF
97 | SPR_FIELD_MASK_SYS_FPCSR_OVF
98 | SPR_FIELD_MASK_SYS_FPCSR_UNF
99 | SPR_FIELD_MASK_SYS_FPCSR_INF
100 | SPR_FIELD_MASK_SYS_FPCSR_DZF
101 | SPR_FIELD_MASK_SYS_FPCSR_IXF
))
103 SIM_DESC sd
= CPU_STATE (current_cpu
);
105 /* If the sim is running in fast mode, i.e. not profiling,
106 per-instruction callbacks are not triggered which would allow
107 us to track the PC. This means we cannot track which
108 instruction caused the FPU error. */
109 if (!PROFILE_ANY_P (current_cpu
) && !TRACE_ANY_P (current_cpu
))
111 (sd
, "WARNING: ignoring fpu error caught in fast mode.\n");
113 or1k32bf_exception (current_cpu
, GET_H_SYS_PPC (), EXCEPT_FPE
);
119 /* Implement the OpenRISC exception function. This is mostly used by the
120 CGEN generated files. For example, this is used when handling a
121 overflow exception during a multiplication instruction. */
124 or1k32bf_exception (sim_cpu
*current_cpu
, USI pc
, USI exnum
)
126 SIM_DESC sd
= CPU_STATE (current_cpu
);
127 struct or1k_sim_cpu
*or1k_cpu
= OR1K_SIM_CPU (current_cpu
);
129 if (exnum
== EXCEPT_TRAP
)
131 /* Trap, used for breakpoints, sends control back to gdb breakpoint
133 sim_engine_halt (sd
, current_cpu
, NULL
, pc
, sim_stopped
, SIM_SIGTRAP
);
139 /* Calculate the exception program counter. */
147 SET_H_SYS_EPCR0 (pc
+ 4 - (or1k_cpu
->delay_slot
? 4 : 0));
154 SET_H_SYS_EPCR0 (pc
- (or1k_cpu
->delay_slot
? 4 : 0));
158 sim_io_error (sd
, "unexpected exception 0x%x raised at PC 0x%08x",
163 /* Store the current SR into ESR0. */
164 SET_H_SYS_ESR0 (GET_H_SYS_SR ());
166 /* Indicate in SR if the failed instruction is in delay slot or not. */
167 SET_H_SYS_SR_DSX (or1k_cpu
->delay_slot
);
169 or1k_cpu
->next_delay_slot
= 0;
171 /* Jump program counter into handler. */
173 (GET_H_SYS_SR_EPH () ? 0xf0000000 : 0x00000000) + (exnum
<< 8);
175 sim_engine_restart (sd
, current_cpu
, NULL
, handler_pc
);
179 /* Implement the return from exception instruction. This is used to return
180 the CPU to its previous state from within an exception handler. */
183 or1k32bf_rfe (sim_cpu
*current_cpu
)
185 struct or1k_sim_cpu
*or1k_cpu
= OR1K_SIM_CPU (current_cpu
);
187 SET_H_SYS_SR (GET_H_SYS_ESR0 ());
190 or1k_cpu
->next_delay_slot
= 0;
192 sim_engine_restart (CPU_STATE (current_cpu
), current_cpu
, NULL
,
196 /* Implement the move from SPR instruction. This is used to read from the
197 CPU's special purpose registers. */
200 or1k32bf_mfspr (sim_cpu
*current_cpu
, USI addr
)
202 SIM_DESC sd
= CPU_STATE (current_cpu
);
205 if (!GET_H_SYS_SR_SM () && !GET_H_SYS_SR_SUMRA ())
207 sim_io_eprintf (sd
, "WARNING: l.mfspr in user mode (SR 0x%x)\n",
215 val
= GET_H_SPR (addr
);
220 case SPR_ADDR (SYS
, VR
):
221 case SPR_ADDR (SYS
, UPR
):
222 case SPR_ADDR (SYS
, CPUCFGR
):
223 case SPR_ADDR (SYS
, SR
):
224 case SPR_ADDR (SYS
, PPC
):
225 case SPR_ADDR (SYS
, FPCSR
):
226 case SPR_ADDR (SYS
, EPCR0
):
227 case SPR_ADDR (MAC
, MACLO
):
228 case SPR_ADDR (MAC
, MACHI
):
232 if (addr
< SPR_ADDR (SYS
, GPR0
) || addr
> SPR_ADDR (SYS
, GPR511
))
241 sim_io_eprintf (sd
, "WARNING: l.mfspr with invalid SPR address 0x%x\n", addr
);
246 /* Implement the move to SPR instruction. This is used to write too the
247 CPU's special purpose registers. */
250 or1k32bf_mtspr (sim_cpu
*current_cpu
, USI addr
, USI val
)
252 SIM_DESC sd
= CPU_STATE (current_cpu
);
253 struct or1k_sim_cpu
*or1k_cpu
= OR1K_SIM_CPU (current_cpu
);
255 if (!GET_H_SYS_SR_SM () && !GET_H_SYS_SR_SUMRA ())
258 (sd
, "WARNING: l.mtspr with address 0x%x in user mode (SR 0x%x)\n",
259 addr
, GET_H_SYS_SR ());
269 case SPR_ADDR (SYS
, FPCSR
):
270 case SPR_ADDR (SYS
, EPCR0
):
271 case SPR_ADDR (SYS
, ESR0
):
272 case SPR_ADDR (MAC
, MACHI
):
273 case SPR_ADDR (MAC
, MACLO
):
274 SET_H_SPR (addr
, val
);
277 case SPR_ADDR (SYS
, SR
):
278 SET_H_SPR (addr
, val
);
282 case SPR_ADDR (SYS
, NPC
):
283 or1k_cpu
->next_delay_slot
= 0;
285 sim_engine_restart (sd
, current_cpu
, NULL
, val
);
288 case SPR_ADDR (TICK
, TTMR
):
289 /* Allow some registers to be silently cleared. */
292 (sd
, "WARNING: l.mtspr to SPR address 0x%x with invalid value 0x%x\n",
297 if (addr
>= SPR_ADDR (SYS
, GPR0
) && addr
<= SPR_ADDR (SYS
, GPR511
))
298 SET_H_SPR (addr
, val
);
308 sim_io_eprintf (sd
, "WARNING: l.mtspr with invalid SPR address 0x%x\n", addr
);