]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/or1k/traps.c
sim: split sim-signal.h include out
[thirdparty/binutils-gdb.git] / sim / or1k / traps.c
CommitLineData
fa8b7c21 1/* OpenRISC exception, interrupts, syscall and trap support
3666a048 2 Copyright (C) 2017-2021 Free Software Foundation, Inc.
fa8b7c21
SH
3
4 This file is part of GDB, the GNU debugger.
5
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.
10
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.
15
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/>. */
18
6df01ab8
MF
19/* This must come before any other includes. */
20#include "defs.h"
21
fa8b7c21
SH
22#define WANT_CPU_OR1K32BF
23#define WANT_CPU
24
25#include "sim-main.h"
1fef66b0 26#include "sim-signal.h"
fa8b7c21
SH
27#include "cgen-ops.h"
28
29/* Implement the sim invalid instruction function. This will set the error
30 effective address to that of the invalid instruction then call the
31 exception handler. */
32
33SEM_PC
34sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc)
35{
36 SET_H_SYS_EEAR0 (cia);
37
38#ifdef WANT_CPU_OR1K32BF
39 or1k32bf_exception (current_cpu, cia, EXCEPT_ILLEGAL);
40#endif
41
42 return vpc;
43}
44
45/* Generate the appropriate OpenRISC fpu exception based on the status code from
46 the sim fpu. */
47void
48or1k32bf_fpu_error (CGEN_FPU* fpu, int status)
49{
50 SIM_CPU *current_cpu = (SIM_CPU *)fpu->owner;
51
52 /* If floating point exceptions are enabled. */
53 if (GET_H_SYS_FPCSR_FPEE() != 0)
54 {
55 /* Set all of the status flag bits. */
56 if (status
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);
67
68 if (status & sim_fpu_status_invalid_snan)
69 SET_H_SYS_FPCSR_SNF (1);
70
71 if (status & sim_fpu_status_invalid_qnan)
72 SET_H_SYS_FPCSR_QNF (1);
73
74 if (status & sim_fpu_status_overflow)
75 SET_H_SYS_FPCSR_OVF (1);
76
77 if (status & sim_fpu_status_underflow)
78 SET_H_SYS_FPCSR_UNF (1);
79
80 if (status
81 & (sim_fpu_status_invalid_isi
82 | sim_fpu_status_invalid_idi))
83 SET_H_SYS_FPCSR_INF (1);
84
85 if (status & sim_fpu_status_invalid_div0)
86 SET_H_SYS_FPCSR_DZF (1);
87
88 if (status & sim_fpu_status_inexact)
89 SET_H_SYS_FPCSR_IXF (1);
90
91 /* If any of the exception bits were actually set. */
92 if (GET_H_SYS_FPCSR()
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))
101 {
102 SIM_DESC sd = CPU_STATE (current_cpu);
103
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. */
906192d7 108 if (!PROFILE_ANY_P (current_cpu) && !TRACE_ANY_P (current_cpu))
fa8b7c21
SH
109 sim_io_eprintf
110 (sd, "WARNING: ignoring fpu error caught in fast mode.\n");
111 else
112 or1k32bf_exception (current_cpu, GET_H_SYS_PPC (), EXCEPT_FPE);
113 }
114 }
115}
116
117
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. */
121
122void
123or1k32bf_exception (sim_cpu *current_cpu, USI pc, USI exnum)
124{
125 SIM_DESC sd = CPU_STATE (current_cpu);
126
127 if (exnum == EXCEPT_TRAP)
128 {
129 /* Trap, used for breakpoints, sends control back to gdb breakpoint
130 handling. */
131 sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
132 }
133 else
134 {
e998918e 135 IADDR handler_pc;
fa8b7c21
SH
136
137 /* Calculate the exception program counter. */
138 switch (exnum)
139 {
140 case EXCEPT_RESET:
141 break;
142
143 case EXCEPT_FPE:
144 case EXCEPT_SYSCALL:
145 SET_H_SYS_EPCR0 (pc + 4 - (current_cpu->delay_slot ? 4 : 0));
146 break;
147
148 case EXCEPT_BUSERR:
149 case EXCEPT_ALIGN:
150 case EXCEPT_ILLEGAL:
151 case EXCEPT_RANGE:
152 SET_H_SYS_EPCR0 (pc - (current_cpu->delay_slot ? 4 : 0));
153 break;
154
155 default:
156 sim_io_error (sd, "unexpected exception 0x%x raised at PC 0x%08x",
157 exnum, pc);
158 break;
159 }
160
161 /* Store the current SR into ESR0. */
162 SET_H_SYS_ESR0 (GET_H_SYS_SR ());
163
164 /* Indicate in SR if the failed instruction is in delay slot or not. */
165 SET_H_SYS_SR_DSX (current_cpu->delay_slot);
166
167 current_cpu->next_delay_slot = 0;
168
169 /* Jump program counter into handler. */
e998918e
MF
170 handler_pc =
171 (GET_H_SYS_SR_EPH () ? 0xf0000000 : 0x00000000) + (exnum << 8);
fa8b7c21
SH
172
173 sim_engine_restart (sd, current_cpu, NULL, handler_pc);
174 }
175}
176
177/* Implement the return from exception instruction. This is used to return
178 the CPU to its previous state from within an exception handler. */
179
180void
181or1k32bf_rfe (sim_cpu *current_cpu)
182{
183 SET_H_SYS_SR (GET_H_SYS_ESR0 ());
184 SET_H_SYS_SR_FO (1);
185
186 current_cpu->next_delay_slot = 0;
187
188 sim_engine_restart (CPU_STATE (current_cpu), current_cpu, NULL,
189 GET_H_SYS_EPCR0 ());
190}
191
192/* Implement the move from SPR instruction. This is used to read from the
193 CPU's special purpose registers. */
194
195USI
196or1k32bf_mfspr (sim_cpu *current_cpu, USI addr)
197{
198 SIM_DESC sd = CPU_STATE (current_cpu);
e998918e 199 SI val;
fa8b7c21
SH
200
201 if (!GET_H_SYS_SR_SM () && !GET_H_SYS_SR_SUMRA ())
202 {
203 sim_io_eprintf (sd, "WARNING: l.mfspr in user mode (SR 0x%x)\n",
204 GET_H_SYS_SR ());
205 return 0;
206 }
207
208 if (addr >= NUM_SPR)
209 goto bad_address;
210
e998918e 211 val = GET_H_SPR (addr);
fa8b7c21
SH
212
213 switch (addr)
214 {
215
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):
225 break;
226
227 default:
228 if (addr < SPR_ADDR (SYS, GPR0) || addr > SPR_ADDR (SYS, GPR511))
229 goto bad_address;
230 break;
231
232 }
233
234 return val;
235
236bad_address:
237 sim_io_eprintf (sd, "WARNING: l.mfspr with invalid SPR address 0x%x\n", addr);
238 return 0;
239
240}
241
242/* Implement the move to SPR instruction. This is used to write too the
243 CPU's special purpose registers. */
244
245void
246or1k32bf_mtspr (sim_cpu *current_cpu, USI addr, USI val)
247{
248 SIM_DESC sd = CPU_STATE (current_cpu);
249
250 if (!GET_H_SYS_SR_SM () && !GET_H_SYS_SR_SUMRA ())
251 {
252 sim_io_eprintf
253 (sd, "WARNING: l.mtspr with address 0x%x in user mode (SR 0x%x)\n",
254 addr, GET_H_SYS_SR ());
255 return;
256 }
257
258 if (addr >= NUM_SPR)
259 goto bad_address;
260
261 switch (addr)
262 {
263
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);
270 break;
271
272 case SPR_ADDR (SYS, SR):
273 SET_H_SPR (addr, val);
274 SET_H_SYS_SR_FO (1);
275 break;
276
277 case SPR_ADDR (SYS, NPC):
278 current_cpu->next_delay_slot = 0;
279
280 sim_engine_restart (CPU_STATE (current_cpu), current_cpu, NULL, val);
281 break;
282
283 case SPR_ADDR (TICK, TTMR):
284 /* Allow some registers to be silently cleared. */
285 if (val != 0)
286 sim_io_eprintf
287 (sd, "WARNING: l.mtspr to SPR address 0x%x with invalid value 0x%x\n",
288 addr, val);
289 break;
290
291 default:
292 if (addr >= SPR_ADDR (SYS, GPR0) && addr <= SPR_ADDR (SYS, GPR511))
293 SET_H_SPR (addr, val);
294 else
295 goto bad_address;
296 break;
297
298 }
299
300 return;
301
302bad_address:
303 sim_io_eprintf (sd, "WARNING: l.mtspr with invalid SPR address 0x%x\n", addr);
304
305}