1 /* OpenRISC exception, interrupts, syscall and trap support
2 Copyright (C) 2017-2022 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
26 #include "sim-signal.h"
29 /* Implement the sim invalid instruction function. This will set the error
30 effective address to that of the invalid instruction then call the
34 sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc)
36 SET_H_SYS_EEAR0 (cia);
38 #ifdef WANT_CPU_OR1K32BF
39 or1k32bf_exception (current_cpu, cia, EXCEPT_ILLEGAL);
45 /* Generate the appropriate OpenRISC fpu exception based on the status code from
48 or1k32bf_fpu_error (CGEN_FPU* fpu, int status)
50 SIM_CPU *current_cpu = (SIM_CPU *)fpu->owner;
52 /* If floating point exceptions are enabled. */
53 if (GET_H_SYS_FPCSR_FPEE() != 0)
55 /* Set all of the status flag bits. */
57 & (sim_fpu_status_invalid_snan
58 | sim_fpu_status_invalid_qnan
59 | sim_fpu_status_invalid_isi
60 | sim_fpu_status_invalid_idi
61 | sim_fpu_status_invalid_zdz
62 | sim_fpu_status_invalid_imz
63 | sim_fpu_status_invalid_cvi
64 | sim_fpu_status_invalid_cmp
65 | sim_fpu_status_invalid_sqrt))
66 SET_H_SYS_FPCSR_IVF (1);
68 if (status & sim_fpu_status_invalid_snan)
69 SET_H_SYS_FPCSR_SNF (1);
71 if (status & sim_fpu_status_invalid_qnan)
72 SET_H_SYS_FPCSR_QNF (1);
74 if (status & sim_fpu_status_overflow)
75 SET_H_SYS_FPCSR_OVF (1);
77 if (status & sim_fpu_status_underflow)
78 SET_H_SYS_FPCSR_UNF (1);
81 & (sim_fpu_status_invalid_isi
82 | sim_fpu_status_invalid_idi))
83 SET_H_SYS_FPCSR_INF (1);
85 if (status & sim_fpu_status_invalid_div0)
86 SET_H_SYS_FPCSR_DZF (1);
88 if (status & sim_fpu_status_inexact)
89 SET_H_SYS_FPCSR_IXF (1);
91 /* If any of the exception bits were actually set. */
93 & (SPR_FIELD_MASK_SYS_FPCSR_IVF
94 | SPR_FIELD_MASK_SYS_FPCSR_SNF
95 | SPR_FIELD_MASK_SYS_FPCSR_QNF
96 | SPR_FIELD_MASK_SYS_FPCSR_OVF
97 | SPR_FIELD_MASK_SYS_FPCSR_UNF
98 | SPR_FIELD_MASK_SYS_FPCSR_INF
99 | SPR_FIELD_MASK_SYS_FPCSR_DZF
100 | SPR_FIELD_MASK_SYS_FPCSR_IXF))
102 SIM_DESC sd = CPU_STATE (current_cpu);
104 /* If the sim is running in fast mode, i.e. not profiling,
105 per-instruction callbacks are not triggered which would allow
106 us to track the PC. This means we cannot track which
107 instruction caused the FPU error. */
108 if (!PROFILE_ANY_P (current_cpu) && !TRACE_ANY_P (current_cpu))
110 (sd, "WARNING: ignoring fpu error caught in fast mode.\n");
112 or1k32bf_exception (current_cpu, GET_H_SYS_PPC (), EXCEPT_FPE);
118 /* Implement the OpenRISC exception function. This is mostly used by the
119 CGEN generated files. For example, this is used when handling a
120 overflow exception during a multiplication instruction. */
123 or1k32bf_exception (sim_cpu *current_cpu, USI pc, USI exnum)
125 SIM_DESC sd = CPU_STATE (current_cpu);
127 if (exnum == EXCEPT_TRAP)
129 /* Trap, used for breakpoints, sends control back to gdb breakpoint
131 sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
137 /* Calculate the exception program counter. */
145 SET_H_SYS_EPCR0 (pc + 4 - (current_cpu->delay_slot ? 4 : 0));
152 SET_H_SYS_EPCR0 (pc - (current_cpu->delay_slot ? 4 : 0));
156 sim_io_error (sd, "unexpected exception 0x%x raised at PC 0x%08x",
161 /* Store the current SR into ESR0. */
162 SET_H_SYS_ESR0 (GET_H_SYS_SR ());
164 /* Indicate in SR if the failed instruction is in delay slot or not. */
165 SET_H_SYS_SR_DSX (current_cpu->delay_slot);
167 current_cpu->next_delay_slot = 0;
169 /* Jump program counter into handler. */
171 (GET_H_SYS_SR_EPH () ? 0xf0000000 : 0x00000000) + (exnum << 8);
173 sim_engine_restart (sd, current_cpu, NULL, handler_pc);
177 /* Implement the return from exception instruction. This is used to return
178 the CPU to its previous state from within an exception handler. */
181 or1k32bf_rfe (sim_cpu *current_cpu)
183 SET_H_SYS_SR (GET_H_SYS_ESR0 ());
186 current_cpu->next_delay_slot = 0;
188 sim_engine_restart (CPU_STATE (current_cpu), current_cpu, NULL,
192 /* Implement the move from SPR instruction. This is used to read from the
193 CPU's special purpose registers. */
196 or1k32bf_mfspr (sim_cpu *current_cpu, USI addr)
198 SIM_DESC sd = CPU_STATE (current_cpu);
201 if (!GET_H_SYS_SR_SM () && !GET_H_SYS_SR_SUMRA ())
203 sim_io_eprintf (sd, "WARNING: l.mfspr in user mode (SR 0x%x)\n",
211 val = GET_H_SPR (addr);
216 case SPR_ADDR (SYS, VR):
217 case SPR_ADDR (SYS, UPR):
218 case SPR_ADDR (SYS, CPUCFGR):
219 case SPR_ADDR (SYS, SR):
220 case SPR_ADDR (SYS, PPC):
221 case SPR_ADDR (SYS, FPCSR):
222 case SPR_ADDR (SYS, EPCR0):
223 case SPR_ADDR (MAC, MACLO):
224 case SPR_ADDR (MAC, MACHI):
228 if (addr < SPR_ADDR (SYS, GPR0) || addr > SPR_ADDR (SYS, GPR511))
237 sim_io_eprintf (sd, "WARNING: l.mfspr with invalid SPR address 0x%x\n", addr);
242 /* Implement the move to SPR instruction. This is used to write too the
243 CPU's special purpose registers. */
246 or1k32bf_mtspr (sim_cpu *current_cpu, USI addr, USI val)
248 SIM_DESC sd = CPU_STATE (current_cpu);
250 if (!GET_H_SYS_SR_SM () && !GET_H_SYS_SR_SUMRA ())
253 (sd, "WARNING: l.mtspr with address 0x%x in user mode (SR 0x%x)\n",
254 addr, GET_H_SYS_SR ());
264 case SPR_ADDR (SYS, FPCSR):
265 case SPR_ADDR (SYS, EPCR0):
266 case SPR_ADDR (SYS, ESR0):
267 case SPR_ADDR (MAC, MACHI):
268 case SPR_ADDR (MAC, MACLO):
269 SET_H_SPR (addr, val);
272 case SPR_ADDR (SYS, SR):
273 SET_H_SPR (addr, val);
277 case SPR_ADDR (SYS, NPC):
278 current_cpu->next_delay_slot = 0;
280 sim_engine_restart (CPU_STATE (current_cpu), current_cpu, NULL, val);
283 case SPR_ADDR (TICK, TTMR):
284 /* Allow some registers to be silently cleared. */
287 (sd, "WARNING: l.mtspr to SPR address 0x%x with invalid value 0x%x\n",
292 if (addr >= SPR_ADDR (SYS, GPR0) && addr <= SPR_ADDR (SYS, GPR511))
293 SET_H_SPR (addr, val);
303 sim_io_eprintf (sd, "WARNING: l.mtspr with invalid SPR address 0x%x\n", addr);